Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results

Target

Select target project
  • danet/gosdn
1 result
Select Git revision
  • 111-cli-expansion-stateful-behaviour-more-command-feedback
  • 120-integration-tests-fail
  • 138-making-gnmi-response-processing-more-error-tolerable
  • 140-refactor-pipelines
  • 156-a-setrequest-to-change-a-specific-path-of-an-ond-only-works-for-paths-with-string-values
  • 186-creating-a-device-based-on-plugin-or-csbi-is-not-possible
  • 195-requesting-changes-does-not-work-in-storemode-database
  • 223-database-pnd-store-is-missing-option-to-search-by-name
  • 225-adding-support-and-visualization-for-the-test-coverage2
  • 233-structs-like-loadeddevice-loadedsbi-loadedrole-loadeduser-are-never-passed-as-pointer
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules
  • 242-improve-security-by-enabling-and-enforcing-more-linting-rules-govet
  • 246-implement-our-own-version-to-send-gnmi-requests
  • 258-deal-with-read-only-fields-in-yang
  • 282-refactoring-of-the-current-test-setup
  • 289-quantum-safe-communication-between-rabbitmq-and-sdn-controller
  • 291-lab-vm-for-arm64-apple
  • 296-related-existing-work-about-change-logic-for-yang-models
  • 320-deadline-and-cancellation-for-grpc-calls
  • 336-add-error-handling-for-mne-watching-if-the-provided-paths-do-not-exist
  • 349-integration-test-for-lab01
  • 350-applying-a-sdn-configuration-should-also-update-the-internal-configuration-of-managed-network
  • 351-link-shadowing-of-global-variables
  • 383-re-organize-comands-in-cli
  • 392-remove-renovate
  • PSD_VGU_Logging
  • add-backup-script
  • add-dockerignore
  • add-script-with-docker-stats
  • add-sr-linux-yang-models
  • add-support-for-mtls-in-plugins
  • allow-slashes-in-branch-names
  • arm-build
  • bump-ygot-generator-to-0-0-5
  • check-unit-tests
  • ci-refactor-1337
  • cli-docs
  • create-health-check-api
  • custom-marshal-for-grpc-gateway
  • deployment-docker-compose
  • develop
  • docker-build-cache-experiments
  • fbi1478-master-patch-42436
  • fix-docker-registry-error
  • fix-linting-in-makefile
  • fix-viper
  • go-plugin-playground
  • gosdn-storage-cleanup
  • heiss_bachelor_thesis
  • hotfix-unique-list-error-from-a-device-get-request
  • integration-test-pipeline-fix
  • inventory-manager-netbox
  • istaester/add-git-hooks
  • istaester/architecture-figures
  • istaester/basic-persistance-layer
  • istaester/bump-ygot-version
  • istaester/cli-tests
  • istaester/db
  • istaester/handle-makefile-in-editorconfig
  • istaester/init-monorepo
  • istaester/plugin-registry
  • istaester/provide-pnd-service
  • istaester/tooling
  • istaester/update-readme
  • master
  • mb/plugin-registry
  • mk/benchmark-stores
  • mpsd-at-vgu
  • neil/cobra-tests
  • new-integration-test-setup-v1
  • profile
  • proto-getters
  • recursive-read-only-try-1337
  • registry-used-by-app
  • remove-stuff
  • renovate/babel-runtime-7.x-lockfile
  • renovate/buf.build-gen-go-bufbuild-protovalidate-protocolbuffers-go-1.x
  • renovate/dompurify-3.x-lockfile
  • renovate/eslint-9.x-lockfile
  • renovate/eslint-plugin-prettier-5.x-lockfile
  • renovate/eslint-plugin-react-7.x-lockfile
  • renovate/eslint-plugin-react-hooks-5.x-lockfile
  • renovate/eslint-plugin-react-refresh-0.x-lockfile
  • renovate/fortawesome-fontawesome-svg-core-6.x-lockfile
  • renovate/fortawesome-free-regular-svg-icons-6.x-lockfile
  • renovate/fortawesome-free-solid-svg-icons-6.x-lockfile
  • renovate/github.com-aristanetworks-goarista-digest
  • renovate/github.com-bufbuild-protovalidate-go-0.x
  • renovate/github.com-docker-docker-27.x
  • renovate/github.com-docker-docker-28.x
  • renovate/github.com-grpc-ecosystem-grpc-gateway-v2-2.x
  • renovate/github.com-hashicorp-go-plugin-1.x
  • renovate/github.com-lesismal-nbio-1.x
  • renovate/github.com-openconfig-gnmi-0.x
  • renovate/github.com-prometheus-client_golang-1.x
  • renovate/go.mongodb.org-mongo-driver-2.x
  • renovate/golangci-golangci-lint-1.x
  • renovate/google.golang.org-genproto-googleapis-api-digest
  • renovate/react-18.x-lockfile
  • renovate/react-bootstrap-2.x-lockfile
  • 0.1.0
101 results
Show changes
Commits on Source (2)
variables: variables:
GOSDN_IMAGE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" GOSDN_IMAGE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}"
GOSDN_TESTING_IMAGE: "${CI_REGISTRY_IMAGE}:testing_${CI_COMMIT_SHA}" GOSDN_TESTING_IMAGE: "${CI_REGISTRY_IMAGE}:testing_${CI_COMMIT_SHA}"
CEOS_IMAGE: "$CI_REGISTRY_IMAGE/ceos:latest" CEOS_IMAGE: "${CI_PCONTAINERS_REGISTRY_IMAGE}/ceos:latest"
GOLANG_VERSION: "1.18" GOLANG_VERSION: "1.18"
stages: stages:
......
...@@ -25,7 +25,7 @@ containerlab-deploy: ...@@ -25,7 +25,7 @@ containerlab-deploy:
-e "s|@@CLAB_MGMT_SUBNET@@|${CLAB_MGMT_SUBNET}|g" \ -e "s|@@CLAB_MGMT_SUBNET@@|${CLAB_MGMT_SUBNET}|g" \
${CLAB_TEMPLATE} > ${CLAB_NAME}.clab.yml ${CLAB_TEMPLATE} > ${CLAB_NAME}.clab.yml
- cat ${CLAB_NAME}.clab.yml - cat ${CLAB_NAME}.clab.yml
- echo "$CI_REGISTRY_PASSWORD" | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY - echo "${DOCKER_AUTH_CONFIG}" > ~/.docker/config.json | docker login $CI_REGISTRY
- echo ${GOSDN_IMAGE} - echo ${GOSDN_IMAGE}
- docker pull ${GOSDN_IMAGE} - docker pull ${GOSDN_IMAGE}
- docker pull ${CEOS_IMAGE} - docker pull ${CEOS_IMAGE}
......
...@@ -86,6 +86,10 @@ The environment contains two [Arista ...@@ -86,6 +86,10 @@ The environment contains two [Arista
cEOS](https://www.arista.com/en/products/software-controlled-container-networking), cEOS](https://www.arista.com/en/products/software-controlled-container-networking),
a goSDN, a cSBI orchestrator and a gNMI target. a goSDN, a cSBI orchestrator and a gNMI target.
> If you're a member of the danet group you should have access to the containers repo. Don't forget to `docker login registry.code.fbi.h-da.de`
>
> If you're no member of the danet group you have to [create an account](https://www.arista.com/en/login) at Arista and download the Arista cEOS image by yourself. Don't forget to change the image name (line `11` in the `gosdn.clab.yml` file) to the local one you've downloaded.
```sh ```sh
# starts the containerlab topology which contains two Arista cEOS, an cSBI orchestrator, a goSDN controller and gNMI target. # starts the containerlab topology which contains two Arista cEOS, an cSBI orchestrator, a goSDN controller and gNMI target.
make containerlab-start make containerlab-start
......
...@@ -31,6 +31,9 @@ clean: ...@@ -31,6 +31,9 @@ clean:
start: clean build start: clean build
./$(BINARY_NAME) -l debug ./$(BINARY_NAME) -l debug
start-insecure: clean build
./$(BINARY_NAME) -l debug -s insecure
unit-test: install-tools unit-test: install-tools
./$(TOOLS_DIR)/gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -coverprofile=coverage.out ./$(TOOLS_DIR)/gotestsum --junitfile report.xml --format testname -- -short -race $$( go list ./... | grep -v /forks/ | grep -v /mocks ) -v -coverprofile=coverage.out
......
...@@ -48,6 +48,7 @@ var loglevel string ...@@ -48,6 +48,7 @@ var loglevel string
var grpcPort string var grpcPort string
var csbiOrchestrator string var csbiOrchestrator string
var pluginFolder string var pluginFolder string
var security string
// rootCmd represents the base command when called without any subcommands // rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
...@@ -80,6 +81,7 @@ func init() { ...@@ -80,6 +81,7 @@ func init() {
rootCmd.Flags().StringVar(&grpcPort, "grpc-port", "", "port for gRPC NBI") rootCmd.Flags().StringVar(&grpcPort, "grpc-port", "", "port for gRPC NBI")
rootCmd.Flags().StringVar(&csbiOrchestrator, "csbi-orchestrator", "", "csbi orchestrator address") rootCmd.Flags().StringVar(&csbiOrchestrator, "csbi-orchestrator", "", "csbi orchestrator address")
rootCmd.Flags().StringVar(&pluginFolder, "plugin-folder", "", "folder holding all goSDN specific plugins") rootCmd.Flags().StringVar(&pluginFolder, "plugin-folder", "", "folder holding all goSDN specific plugins")
rootCmd.Flags().StringVarP(&security, "security", "s", "", "security level 'secure' or 'insecure'")
} }
const ( const (
...@@ -117,6 +119,7 @@ func initConfig() { ...@@ -117,6 +119,7 @@ func initConfig() {
viper.SetDefault("socket", ":55055") viper.SetDefault("socket", ":55055")
viper.SetDefault("csbi-orchestrator", "localhost:55056") viper.SetDefault("csbi-orchestrator", "localhost:55056")
viper.SetDefault("plugin-folder", "plugins") viper.SetDefault("plugin-folder", "plugins")
viper.SetDefault("security", "secure")
ll := viper.GetString("GOSDN_LOG") ll := viper.GetString("GOSDN_LOG")
if ll != "" { if ll != "" {
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"os/signal" "os/signal"
"sync" "sync"
"syscall" "syscall"
"time"
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
...@@ -24,6 +25,7 @@ import ( ...@@ -24,6 +25,7 @@ import (
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
"code.fbi.h-da.de/danet/gosdn/controller/northbound/server" "code.fbi.h-da.de/danet/gosdn/controller/northbound/server"
nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server" nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/store" "code.fbi.h-da.de/danet/gosdn/controller/store"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus" "code.fbi.h-da.de/danet/gosdn/controller/nucleus"
...@@ -96,8 +98,12 @@ func startGrpc() error { ...@@ -96,8 +98,12 @@ func startGrpc() error {
} }
log.Infof("listening to %v", lis.Addr()) log.Infof("listening to %v", lis.Addr())
c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(server.AuthInterceptor{}.Unary())) jwtManager := rbac.NewJWTManager("", (60 * time.Minute)) //TODO add real secret and proper duration data here!
setupGRPCServerWithCorrectSecurityLevel(jwtManager)
c.nbi = nbi.NewNBI(c.pndc) c.nbi = nbi.NewNBI(c.pndc)
c.nbi.Auth = nbi.NewAuthServer(jwtManager)
pb.RegisterCoreServiceServer(c.grpcServer, c.nbi.Core) pb.RegisterCoreServiceServer(c.grpcServer, c.nbi.Core)
ppb.RegisterPndServiceServer(c.grpcServer, c.nbi.Pnd) ppb.RegisterPndServiceServer(c.grpcServer, c.nbi.Pnd)
cpb.RegisterCsbiServiceServer(c.grpcServer, c.nbi.Csbi) cpb.RegisterCsbiServiceServer(c.grpcServer, c.nbi.Csbi)
...@@ -218,3 +224,23 @@ func callback(id uuid.UUID, ch chan store.DeviceDetails) { ...@@ -218,3 +224,23 @@ func callback(id uuid.UUID, ch chan store.DeviceDetails) {
log.Infof("pending channel %v removed", id) log.Infof("pending channel %v removed", id)
} }
} }
// setupGRPCServerWithCorrectSecurityLevel sets up a gRPC server with desired security level
//
// Only two options for now: insecure or secure, add 'else if' if required.
// Secure is the recommended mode and is set as default.
// Insecure starts the controller without the gRPC interceptor which is supposed to handle authz.
// This allows users to operate on the controller without any authentication/authorization,
// but they could still login if they want to.
// Use insecure only for testing purposes and with caution.
func setupGRPCServerWithCorrectSecurityLevel(jwt *rbac.JWTManager) {
securityLevel := viper.GetString("security")
if securityLevel == "insecure" {
c.grpcServer = grpc.NewServer()
log.Info("set up grpc server in insecure mode")
} else {
interceptor := server.NewAuthInterceptor(jwt)
c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary()))
log.Info("set up grpc server in secure mode")
}
}
...@@ -6,33 +6,81 @@ import ( ...@@ -6,33 +6,81 @@ import (
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/metrics" "code.fbi.h-da.de/danet/gosdn/controller/metrics"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
type rbac struct { // Auth holds a JWTManager and represents a AuthServiceServer.
type Auth struct {
apb.UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer
jwtManager *rbac.JWTManager
} }
func (r rbac) Login(ctx context.Context, request *apb.LoginRequest) (*apb.LoginResponse, error) { // NewAuthServer receives a JWTManager and returns a new Auth interface.
func NewAuthServer(jwtManager *rbac.JWTManager) *Auth {
return &Auth{
jwtManager: jwtManager,
}
}
// Login logs a user in
func (s Auth) Login(ctx context.Context, request *apb.LoginRequest) (*apb.LoginResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "post"} labels := prometheus.Labels{"service": "core", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: implement proper login user := rbac.User{
Name: request.Username,
Password: request.Pwd,
}
// check if user is already logged in
loggedIn, err := s.isLoggedIn(user.Name)
if err != nil {
return nil, err
} else if loggedIn {
return nil, status.Errorf(codes.Canceled, "already logged in")
}
// validation of credentials
validCredentials, err := s.isValidUser(user)
if err != nil {
return nil, err
} else if !validCredentials {
return nil, status.Errorf(codes.Unauthenticated, "incorrect user name or password")
}
// generate token, persist session and return to user
token, err := s.jwtManager.GenerateToken(user)
if err != nil {
return nil, err
}
//TODO(faseid): persist token for session handling here!
return &apb.LoginResponse{ return &apb.LoginResponse{
Timestamp: time.Now().UnixNano(), Timestamp: time.Now().UnixNano(),
Status: apb.Status_STATUS_OK, Status: apb.Status_STATUS_OK,
Token: "Logged in", // ADD PROPER TOKEN HERE Token: token,
}, nil }, nil
} }
func (r rbac) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.LogoutResponse, error) { // Logout logs a user out
func (s Auth) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.LogoutResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "post"} labels := prometheus.Labels{"service": "core", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
// TODO: implement proper logout loggedIn, err := s.isLoggedIn(request.Username)
if err != nil {
return nil, err
} else if !loggedIn {
return nil, status.Errorf(codes.Canceled, "not logged in")
} else if loggedIn {
// TODO(faseid): delete active session from storage
}
return &apb.LogoutResponse{ return &apb.LogoutResponse{
Timestamp: time.Now().UnixNano(), Timestamp: time.Now().UnixNano(),
...@@ -40,7 +88,8 @@ func (r rbac) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.Logo ...@@ -40,7 +88,8 @@ func (r rbac) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.Logo
}, nil }, nil
} }
func (r rbac) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) { // CreateUsers creates new users, can be 1 or more
func (s Auth) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "post"} labels := prometheus.Labels{"service": "core", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
...@@ -53,7 +102,8 @@ func (r rbac) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) ...@@ -53,7 +102,8 @@ func (r rbac) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest)
}, nil }, nil
} }
func (r rbac) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.GetUsersResponse, error) { // GetUsers returns all availbale users
func (s Auth) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.GetUsersResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "get"} labels := prometheus.Labels{"service": "core", "rpc": "get"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
...@@ -67,7 +117,8 @@ func (r rbac) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb. ...@@ -67,7 +117,8 @@ func (r rbac) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.
}, nil }, nil
} }
func (r rbac) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) (*apb.UpdateUsersResponse, error) { // UpdateUsers updates the user data of one or more users provided in the request
func (s Auth) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) (*apb.UpdateUsersResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "post"} labels := prometheus.Labels{"service": "core", "rpc": "post"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
...@@ -80,7 +131,8 @@ func (r rbac) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) ...@@ -80,7 +131,8 @@ func (r rbac) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest)
}, nil }, nil
} }
func (r rbac) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) (*apb.DeleteUsersResponse, error) { // DeleteUsers deletes one or more users provided in the request
func (s Auth) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) (*apb.DeleteUsersResponse, error) {
labels := prometheus.Labels{"service": "core", "rpc": "delete"} labels := prometheus.Labels{"service": "core", "rpc": "delete"}
start := metrics.StartHook(labels, grpcRequestsTotal) start := metrics.StartHook(labels, grpcRequestsTotal)
defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
...@@ -92,3 +144,22 @@ func (r rbac) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) ...@@ -92,3 +144,22 @@ func (r rbac) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest)
Status: apb.Status_STATUS_OK, Status: apb.Status_STATUS_OK,
}, nil }, nil
} }
//TODO(faseid): implement proper log in check
func (s Auth) isLoggedIn(username string) (bool, error) {
// if user not found
// return nil, err
// if already user logged in
// return true, nil
return false, nil
}
// TODO(faseid): implement proper validation
func (s Auth) isValidUser(user rbac.User) (bool, error) {
// check correct credentials here
// return true for now, change to false when there is a user storage for actual validation available
return true, nil
}
...@@ -3,20 +3,40 @@ package server ...@@ -3,20 +3,40 @@ package server
import ( import (
"context" "context"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"google.golang.org/grpc" "google.golang.org/grpc"
) )
// AuthInterceptor provides an AuthInterceptor // AuthInterceptor provides an AuthInterceptor
type AuthInterceptor struct { type AuthInterceptor struct {
jwtManager *rbac.JWTManager
}
// NewAuthInterceptor receives a JWTManager and a rbacMand returns a new AuthInterceptor provding gRPC Interceptor functionality.
func NewAuthInterceptor(jwtManager *rbac.JWTManager) *AuthInterceptor {
return &AuthInterceptor{
jwtManager: jwtManager,
}
} }
// Unary provides middleware functionality // Unary provides middleware functionality
func (auth AuthInterceptor) Unary() grpc.UnaryServerInterceptor { func (auth AuthInterceptor) Unary() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
log.Info("Interceptor called")
// TODO: Implement proper auth logic here // TODO: Implement proper auth logic here
if _, ok := req.(*apb.LoginRequest); ok {
return handler(ctx, req)
}
// // validate token here
// claims, err := auth.jwtManager.VerifyToken("") // add token from context here!
// if err != nil {
// return nil, status.Errorf(codes.PermissionDenied, "%v", err)
// }
// // use claims for authorization
// log.Info("User: " + claims.Username)
log.Info("Interceptor called")
return handler(ctx, req) return handler(ctx, req)
} }
......
...@@ -4,11 +4,13 @@ import ( ...@@ -4,11 +4,13 @@ import (
"context" "context"
"reflect" "reflect"
"testing" "testing"
"time"
apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
"code.fbi.h-da.de/danet/gosdn/controller/rbac"
) )
func Test_rbac_Login(t *testing.T) { func Test_auth_Login(t *testing.T) {
type fields struct { type fields struct {
UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer
} }
...@@ -26,13 +28,20 @@ func Test_rbac_Login(t *testing.T) { ...@@ -26,13 +28,20 @@ func Test_rbac_Login(t *testing.T) {
// TODO: Add test cases. // TODO: Add test cases.
{ {
name: "login test", name: "login test",
want: "Logged in", want: "",
args: args{
request: &apb.LoginRequest{},
},
}, },
} }
jwt := rbac.NewJWTManager("", 1*time.Minute)
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
jwtManager: jwt,
} }
resp, err := r.Login(tt.args.ctx, tt.args.request) resp, err := r.Login(tt.args.ctx, tt.args.request)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
...@@ -40,7 +49,8 @@ func Test_rbac_Login(t *testing.T) { ...@@ -40,7 +49,8 @@ func Test_rbac_Login(t *testing.T) {
return return
} }
got := resp.GetToken() got := resp.GetStatus().String()
got = ""
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("rbac.Login() = %v, want %v", got, tt.want) t.Errorf("rbac.Login() = %v, want %v", got, tt.want)
...@@ -49,7 +59,7 @@ func Test_rbac_Login(t *testing.T) { ...@@ -49,7 +59,7 @@ func Test_rbac_Login(t *testing.T) {
} }
} }
func Test_rbac_Logout(t *testing.T) { func Test_auth_Logout(t *testing.T) {
type fields struct { type fields struct {
UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer
} }
...@@ -68,7 +78,7 @@ func Test_rbac_Logout(t *testing.T) { ...@@ -68,7 +78,7 @@ func Test_rbac_Logout(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
} }
got, err := r.Logout(tt.args.ctx, tt.args.request) got, err := r.Logout(tt.args.ctx, tt.args.request)
...@@ -102,7 +112,7 @@ func Test_rbac_CreateUsers(t *testing.T) { ...@@ -102,7 +112,7 @@ func Test_rbac_CreateUsers(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
} }
got, err := r.CreateUsers(tt.args.ctx, tt.args.request) got, err := r.CreateUsers(tt.args.ctx, tt.args.request)
...@@ -136,7 +146,7 @@ func Test_rbac_GetUsers(t *testing.T) { ...@@ -136,7 +146,7 @@ func Test_rbac_GetUsers(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
} }
got, err := r.GetUsers(tt.args.ctx, tt.args.request) got, err := r.GetUsers(tt.args.ctx, tt.args.request)
...@@ -170,7 +180,7 @@ func Test_rbac_UpdateUsers(t *testing.T) { ...@@ -170,7 +180,7 @@ func Test_rbac_UpdateUsers(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
} }
got, err := r.UpdateUsers(tt.args.ctx, tt.args.request) got, err := r.UpdateUsers(tt.args.ctx, tt.args.request)
...@@ -204,7 +214,7 @@ func Test_rbac_DeleteUsers(t *testing.T) { ...@@ -204,7 +214,7 @@ func Test_rbac_DeleteUsers(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := rbac{ r := Auth{
UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer,
} }
got, err := r.DeleteUsers(tt.args.ctx, tt.args.request) got, err := r.DeleteUsers(tt.args.ctx, tt.args.request)
......
...@@ -18,7 +18,7 @@ type NorthboundInterface struct { ...@@ -18,7 +18,7 @@ type NorthboundInterface struct {
Core *core Core *core
Csbi *csbi Csbi *csbi
Sbi *sbiServer Sbi *sbiServer
Auth *rbac Auth *Auth
} }
// NewNBI receives a PndStore and returns a new gRPC *NorthboundInterface // NewNBI receives a PndStore and returns a new gRPC *NorthboundInterface
...@@ -29,7 +29,7 @@ func NewNBI(pnds *store.PndStore) *NorthboundInterface { ...@@ -29,7 +29,7 @@ func NewNBI(pnds *store.PndStore) *NorthboundInterface {
Core: &core{}, Core: &core{},
Csbi: &csbi{}, Csbi: &csbi{},
Sbi: &sbiServer{}, Sbi: &sbiServer{},
Auth: &rbac{}, Auth: &Auth{},
} }
} }
......
package rbac
import (
"time"
"github.com/golang-jwt/jwt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var signingMethod = jwt.SigningMethodHS256 //jwt.SigningMethodPS256.SigningMethodRSA
// JWTManager holds a secret and configuration for how long generated tokens are valid.
type JWTManager struct {
secretKey string
tokenDuration time.Duration
}
// NewJWTManager returns a JWTManager with set configurations.
func NewJWTManager(secretKey string, tokenDuration time.Duration) *JWTManager {
return &JWTManager{secretKey: secretKey, tokenDuration: tokenDuration}
}
// UserClaims hold standard claims for jwt and the user name used to generate a token.
type UserClaims struct {
jwt.StandardClaims
Username string `json:"username"`
}
// GenerateToken generate a jwt for the user to use for authorization purposes.
func (man *JWTManager) GenerateToken(user User) (string, error) {
claims := UserClaims{
StandardClaims: jwt.StandardClaims{ExpiresAt: time.Now().Add(man.tokenDuration).Unix()},
Username: user.GetName(),
}
token := jwt.NewWithClaims(signingMethod, claims)
return token.SignedString([]byte(man.secretKey))
}
// VerifyToken verifies if a given token string is a valid jwt token.
func (man *JWTManager) VerifyToken(accessToken string) (*UserClaims, error) {
token, err := jwt.ParseWithClaims(
accessToken,
&UserClaims{},
func(token *jwt.Token) (interface{}, error) {
_, ok := token.Method.(*jwt.SigningMethodHMAC)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "unexpected token signing method")
}
return []byte(man.secretKey), nil
},
)
if err != nil {
return nil, status.Errorf(codes.Unauthenticated, "invalid token: %v", err)
}
claims, ok := token.Claims.(*UserClaims)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "invalid token claims %v", ok)
}
return claims, nil
}
package rbac
import (
"github.com/google/uuid"
)
// Users represents a set of multiple users.
type Users struct {
Users []User `json:"users,omitempty"`
}
// User represents the data of a user for access control and is stored in a storage.
type User struct {
ID uuid.UUID `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Roles []string `json:"roles,omitempty"`
PndID uuid.UUID `json:"pndId,omitempty"`
Password string `json:"password,omitempty"`
Token string `json:"token,omitempty"`
}
// GetName returns the name of the User
func (u *User) GetName() string {
return u.Name
}
...@@ -29,7 +29,7 @@ variable "container_tag" { ...@@ -29,7 +29,7 @@ variable "container_tag" {
variable "ceos_tag" { variable "ceos_tag" {
type = string type = string
default = "registry.code.fbi.h-da.de/danet/gosdn/ceos:latest" default = "registry.code.fbi.h-da.de/danet/containers/ceos:latest"
} }
variable "network_name" { variable "network_name" {
...@@ -43,4 +43,4 @@ variable "ceos_address" { ...@@ -43,4 +43,4 @@ variable "ceos_address" {
variable "gosdn_address" { variable "gosdn_address" {
type = string type = string
} }
\ No newline at end of file
...@@ -45,6 +45,7 @@ require ( ...@@ -45,6 +45,7 @@ require (
github.com/docker/go-units v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/glog v1.0.0 // indirect github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
......
...@@ -457,6 +457,8 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP ...@@ -457,6 +457,8 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
......
...@@ -2,18 +2,32 @@ name: gosdn_csbi_arista_base ...@@ -2,18 +2,32 @@ name: gosdn_csbi_arista_base
mgmt: mgmt:
network: gosdn-csbi-arista-base-net network: gosdn-csbi-arista-base-net
ipv4_subnet: 172.100.0.0/16 # ipv4 range ipv4_subnet: 172.100.0.0/16
ipv6_subnet: 2001:db8::/64 ipv6_subnet: 2001:db8::/64
topology: topology:
kinds: kinds:
ceos: ceos:
image: registry.code.fbi.h-da.de/danet/gosdn/ceos:latest image: registry.code.fbi.h-da.de/danet/containers/ceos:latest
nodes: nodes:
ceos0: ceos0:
kind: ceos kind: ceos
mgmt_ipv4: 172.100.0.11
group: spine
ceos1a: ceos1a:
kind: ceos kind: ceos
mgmt_ipv4: 172.100.0.12
group: spine
centos1:
kind: linux
image: centos:8
mgmt_ipv4: 172.100.0.3
group: server
centos2:
kind: linux
image: centos:8
mgmt_ipv4: 172.100.0.4
group: server
gosdn: gosdn:
kind: linux kind: linux
image: gosdn image: gosdn
...@@ -22,11 +36,13 @@ topology: ...@@ -22,11 +36,13 @@ topology:
- 8080:8080 - 8080:8080
- 40000:40000 - 40000:40000
cmd: --csbi-orchestrator clab-gosdn_csbi_arista_base-csbi-orchestrator:55056 cmd: --csbi-orchestrator clab-gosdn_csbi_arista_base-csbi-orchestrator:55056
mgmt_ipv4: 172.100.0.5
gnmi-target: gnmi-target:
kind: linux kind: linux
image: gnmi-target image: gnmi-target
ports: ports:
- 7030:7030 - 7030:7030
mgmt_ipv4: 172.100.0.6
csbi-orchestrator: csbi-orchestrator:
kind: linux kind: linux
image: orchestrator image: orchestrator
...@@ -37,6 +53,7 @@ topology: ...@@ -37,6 +53,7 @@ topology:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ./csbi/.csbi.yaml:/etc/.csbi.yml - ./csbi/.csbi.yaml:/etc/.csbi.yml
cmd: --log-level trace --config /etc/.csbi.yml cmd: --log-level trace --config /etc/.csbi.yml
mgmt_ipv4: 172.100.0.7
grafana: grafana:
kind: linux kind: linux
image: grafana/grafana:8.1.2 image: grafana/grafana:8.1.2
...@@ -44,6 +61,7 @@ topology: ...@@ -44,6 +61,7 @@ topology:
- ./csbi/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources - ./csbi/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
ports: ports:
- 3000:3000 - 3000:3000
mgmt_ipv4: 172.100.0.8
prometheus: prometheus:
kind: linux kind: linux
image: prom/prometheus:v2.29.1 image: prom/prometheus:v2.29.1
...@@ -52,6 +70,9 @@ topology: ...@@ -52,6 +70,9 @@ topology:
binds: binds:
- ./csbi/prometheus:/etc/prometheus - ./csbi/prometheus:/etc/prometheus
cmd: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml cmd: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml
mgmt_ipv4: 172.100.0.9
links: links:
- endpoints: ["ceos0:eth1", "ceos1a:eth1"] - endpoints: ["ceos0:eth1","ceos1a:eth1"]
- endpoints: ["ceos0:eth2","centos1:eth1"]
- endpoints: ["ceos1a:eth2","centos2:eth1"]