X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=capifcore%2Finternal%2Fsecurityservice%2Fsecurity.go;h=ddedc8565422ba26c8a14b883f40e3f0c3c13b6f;hb=b70522851289af2045d3d0c950b053b5673705cd;hp=52d28ceadd2a4299e36b189244b21ef39ee9e05c;hpb=c865c910a6a04fc202c8eb8b6403544c44784d5f;p=nonrtric%2Fplt%2Fsme.git diff --git a/capifcore/internal/securityservice/security.go b/capifcore/internal/securityservice/security.go index 52d28ce..ddedc85 100644 --- a/capifcore/internal/securityservice/security.go +++ b/capifcore/internal/securityservice/security.go @@ -23,12 +23,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,7 +90,8 @@ func (s *Security) PostSecuritiesSecurityIdToken(ctx echo.Context, securityId st } } } - jwtToken, err := s.keycloak.GetToken(accessTokenReq.ClientId, *accessTokenReq.ClientSecret, *accessTokenReq.Scope, "invokerrealm") + data := url.Values{"grant_type": {"client_credentials"}, "client_id": {accessTokenReq.ClientId}, "client_secret": {*accessTokenReq.ClientSecret}} + jwtToken, err := s.keycloak.GetToken("invokerrealm", data) if err != nil { return sendAccessTokenError(ctx, http.StatusBadRequest, securityapi.AccessTokenErrErrorUnauthorizedClient, err.Error()) } @@ -110,11 +113,63 @@ func (s *Security) PostSecuritiesSecurityIdToken(ctx echo.Context, securityId st } func (s *Security) DeleteTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string) error { - return ctx.NoContent(http.StatusNotImplemented) + if _, ok := s.trustedInvokers[apiInvokerId]; ok { + s.deleteTrustedInvoker(apiInvokerId) + } + + return ctx.NoContent(http.StatusNoContent) +} + +func (s *Security) deleteTrustedInvoker(apiInvokerId string) { + s.lock.Lock() + defer s.lock.Unlock() + delete(s.trustedInvokers, apiInvokerId) } func (s *Security) GetTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string, params securityapi.GetTrustedInvokersApiInvokerIdParams) error { - return ctx.NoContent(http.StatusNotImplemented) + + if trustedInvoker, ok := s.trustedInvokers[apiInvokerId]; ok { + updatedInvoker := s.checkParams(trustedInvoker, params) + if updatedInvoker != nil { + err := ctx.JSON(http.StatusOK, updatedInvoker) + if err != nil { + return err + } + } + } else { + return sendCoreError(ctx, http.StatusNotFound, fmt.Sprintf("invoker %s not registered as trusted invoker", apiInvokerId)) + } + + return nil +} + +func (s *Security) checkParams(trustedInvoker securityapi.ServiceSecurity, params securityapi.GetTrustedInvokersApiInvokerIdParams) *securityapi.ServiceSecurity { + emptyString := "" + + var sendAuthenticationInfo = (params.AuthenticationInfo != nil) && *params.AuthenticationInfo + var sendAuthorizationInfo = (params.AuthorizationInfo != nil) && *params.AuthorizationInfo + + if sendAuthenticationInfo && sendAuthorizationInfo { + return &trustedInvoker + } + + data, _ := copystructure.Copy(trustedInvoker) + updatedInvoker, ok := data.(securityapi.ServiceSecurity) + if !ok { + return nil + } + + if !sendAuthenticationInfo { + for i := range updatedInvoker.SecurityInfo { + updatedInvoker.SecurityInfo[i].AuthenticationInfo = &emptyString + } + } + if !sendAuthorizationInfo { + for i := range updatedInvoker.SecurityInfo { + updatedInvoker.SecurityInfo[i].AuthorizationInfo = &emptyString + } + } + return &updatedInvoker } func (s *Security) PutTrustedInvokersApiInvokerId(ctx echo.Context, apiInvokerId string) error { @@ -172,11 +227,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, apiInvokerId) + + 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, apiInvokerId string) []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 {