X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=capifcore%2Finternal%2Fsecurityservice%2Fsecurity.go;h=b3f1d3000e554721e506b040baaee731cda0af62;hb=5493b0faf67fc5b58b575880db528eb2b663d45a;hp=d3d9026979968b04de58ab4c858be8eec299611c;hpb=856821490df816d7343d90f76f729240bd4e00d6;p=nonrtric%2Fplt%2Fsme.git diff --git a/capifcore/internal/securityservice/security.go b/capifcore/internal/securityservice/security.go index d3d9026..b3f1d30 100644 --- a/capifcore/internal/securityservice/security.go +++ b/capifcore/internal/securityservice/security.go @@ -2,7 +2,8 @@ // ========================LICENSE_START================================= // O-RAN-SC // %% -// Copyright (C) 2022: Nordix Foundation +// Copyright (C) 2022-2023: Nordix Foundation +// Copyright (C) 2024: OpenInfra Foundation Europe // %% // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,12 +24,14 @@ package security import ( "fmt" "net/http" + "net/url" "path" "strings" "sync" "github.com/labstack/echo/v4" copystructure "github.com/mitchellh/copystructure" + "k8s.io/utils/strings/slices" "oransc.org/nonrtric/capifcore/internal/common29122" securityapi "oransc.org/nonrtric/capifcore/internal/securityapi" @@ -88,9 +91,18 @@ func (s *Security) PostSecuritiesSecurityIdToken(ctx echo.Context, securityId st } } } - jwtToken, err := s.keycloak.GetToken(accessTokenReq.ClientId, *accessTokenReq.ClientSecret, *accessTokenReq.Scope, "invokerrealm") - if err != nil { - return sendAccessTokenError(ctx, http.StatusBadRequest, securityapi.AccessTokenErrErrorUnauthorizedClient, err.Error()) + data := url.Values{"grant_type": {"client_credentials"}, "client_id": {accessTokenReq.ClientId}, "client_secret": {*accessTokenReq.ClientSecret}} + + var jwtToken keycloak.Jwttoken + var err error + + if s.keycloak != nil { + jwtToken, err = s.keycloak.GetToken("invokerrealm", data) + if err != nil { + return sendAccessTokenError(ctx, http.StatusBadRequest, securityapi.AccessTokenErrErrorUnauthorizedClient, err.Error()) + } + } else { + return sendAccessTokenError(ctx, http.StatusBadRequest, securityapi.AccessTokenErrErrorUnauthorizedClient, "keycloak is nil") } accessTokenResp := securityapi.AccessTokenRsp{ @@ -224,11 +236,86 @@ func (s *Security) prepareNewSecurityContext(newContext *securityapi.ServiceSecu } func (s *Security) PostTrustedInvokersApiInvokerIdDelete(ctx echo.Context, apiInvokerId string) error { - return ctx.NoContent(http.StatusNotImplemented) + var notification securityapi.SecurityNotification + + errMsg := "Unable to revoke invoker due to %s" + + if err := ctx.Bind(¬ification); err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, "invalid format for security notification")) + } + + if err := notification.Validate(); err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err)) + } + + if ss, ok := s.trustedInvokers[apiInvokerId]; ok { + securityInfoCopy := s.revokeTrustedInvoker(&ss, notification) + + if len(securityInfoCopy) == 0 { + s.deleteTrustedInvoker(apiInvokerId) + } else { + ss.SecurityInfo = securityInfoCopy + s.updateTrustedInvoker(ss, apiInvokerId) + } + + } else { + return sendCoreError(ctx, http.StatusNotFound, "the invoker is not register as a trusted invoker") + } + + return ctx.NoContent(http.StatusNoContent) + +} + +func (s *Security) revokeTrustedInvoker(ss *securityapi.ServiceSecurity, notification securityapi.SecurityNotification) []securityapi.SecurityInformation { + + data, _ := copystructure.Copy(ss.SecurityInfo) + securityInfoCopy, _ := data.([]securityapi.SecurityInformation) + + for i, context := range ss.SecurityInfo { + if notification.AefId == context.AefId || slices.Contains(notification.ApiIds, *context.ApiId) { + securityInfoCopy = append(securityInfoCopy[:i], securityInfoCopy[i+1:]...) + } + } + + return securityInfoCopy + } func (s *Security) PostTrustedInvokersApiInvokerIdUpdate(ctx echo.Context, apiInvokerId string) error { - return ctx.NoContent(http.StatusNotImplemented) + var serviceSecurity securityapi.ServiceSecurity + + errMsg := "Unable to update service security context due to %s" + + if err := ctx.Bind(&serviceSecurity); err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, "invalid format for service security context")) + } + + if err := serviceSecurity.Validate(); err != nil { + return sendCoreError(ctx, http.StatusBadRequest, fmt.Sprintf(errMsg, err)) + } + + if _, ok := s.trustedInvokers[apiInvokerId]; ok { + s.updateTrustedInvoker(serviceSecurity, apiInvokerId) + } else { + return sendCoreError(ctx, http.StatusNotFound, "the invoker is not register as a trusted invoker") + } + + uri := ctx.Request().Host + ctx.Request().URL.String() + ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, apiInvokerId)) + + err := ctx.JSON(http.StatusOK, s.trustedInvokers[apiInvokerId]) + if err != nil { + // Something really bad happened, tell Echo that our handler failed + return err + } + + return nil +} + +func (s *Security) updateTrustedInvoker(serviceSecurity securityapi.ServiceSecurity, invokerId string) { + s.lock.Lock() + defer s.lock.Unlock() + s.trustedInvokers[invokerId] = serviceSecurity } func sendAccessTokenError(ctx echo.Context, code int, err securityapi.AccessTokenErrError, message string) error {