From ab205b70f22eff5c1feafa4a78a2d8083cedcebd Mon Sep 17 00:00:00 2001 From: harture Date: Tue, 7 Jan 2020 18:42:15 +0100 Subject: [PATCH 1/3] Add RecoveryCode endpoint --- Gopkg.lock | 10 +-- Gopkg.toml | 2 +- api/management/swagger-api_management.yaml | 27 ++++++++ cmd/keycloakb/keycloak_bridge.go | 3 + pkg/management/authorization.go | 12 ++++ pkg/management/authorization_test.go | 9 +++ pkg/management/component.go | 18 ++++++ pkg/management/component_test.go | 73 ++++++++++++++++++++++ pkg/management/endpoint.go | 11 ++++ pkg/management/endpoint_test.go | 22 +++++++ 10 files changed, 181 insertions(+), 6 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 0c5a856da..fbab30e4f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -40,12 +40,12 @@ revision = "e164d81b968e97a3fc079275352764978e35ab42" [[projects]] - branch = "master" - digest = "1:9f6d4c5d4f68f1195fba4c4fc0b6e10424eaff07965ff0d656dc056f24d5ea04" + branch = "CLOUDTRUST-2147_RecoveryModeAPI" + digest = "1:4ed30ae83a9812587b9c1f6c5d6ffdc38996c9aed45c7a0c71140c0f246672f1" name = "github.com/cloudtrust/keycloak-client" packages = ["."] pruneopts = "UT" - revision = "eaca1582c80f7441ac7baa6d39d68b08e4ac3ffd" + revision = "80397ac336a938078a0a41c7e42aa3f08ef38595" [[projects]] digest = "1:d64c893fc7d2c3d395f421b00d21f0adb8ceffc4d3c90299e732b3985ca16eb4" @@ -138,7 +138,7 @@ version = "v1.3.2" [[projects]] - digest = "1:debcbc62c53851dab1fc881438a65449dd5ffa12f64f059fd6e32b938799513d" + digest = "1:e02b687ade0c19c038ecce3ea326d756519adc4bba1203a9e76d620b12354892" name = "github.com/google/flatbuffers" packages = ["go"] pruneopts = "UT" @@ -173,7 +173,7 @@ version = "v1.0.0" [[projects]] - digest = "1:c266355b17e65dc0128f4a9df906567b28e135b774e0b395aab3d748af0871e2" + digest = "1:9b73396bc7a21f88702fe3d314ca7860843c08f9c787bb47f008075f840df23d" name = "github.com/influxdata/influxdb" packages = [ "client/v2", diff --git a/Gopkg.toml b/Gopkg.toml index ae49796db..2a3a1665b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -32,8 +32,8 @@ [[constraint]] name = "github.com/cloudtrust/keycloak-client" - branch = "master" #version = "v1.2.1" + branch="CLOUDTRUST-2147_RecoveryModeAPI" [[constraint]] name = "github.com/go-kit/kit" diff --git a/api/management/swagger-api_management.yaml b/api/management/swagger-api_management.yaml index fa4d2927e..d1526eaa7 100644 --- a/api/management/swagger-api_management.yaml +++ b/api/management/swagger-api_management.yaml @@ -644,6 +644,33 @@ paths: type: array items: $ref: '#/components/schemas/Credential' + /realms/{realm}/users/{userID}/recovery-code: + post: + tags: + - Credentials + summary: Set a recovery code for the user + parameters: + - name: realm + in: path + description: realm name (not id!) + required: true + schema: + type: string + - name: userID + in: path + description: User id + required: true + schema: + type: string + responses: + 201: + description: successful operation + content: + text/plain: + schema: + type: string + 409: + description: recovery code already set /realms/{realm}/users/{userID}/credentials/{credentialID}: delete: tags: diff --git a/cmd/keycloakb/keycloak_bridge.go b/cmd/keycloakb/keycloak_bridge.go index 415d7a2bb..acfa3c133 100644 --- a/cmd/keycloakb/keycloak_bridge.go +++ b/cmd/keycloakb/keycloak_bridge.go @@ -477,6 +477,7 @@ func main() { SendReminderEmail: prepareEndpoint(management.MakeSendReminderEmailEndpoint(keycloakComponent), "send_reminder_email_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), SendNewEnrolmentCode: prepareEndpoint(management.MakeSendNewEnrolmentCodeEndpoint(keycloakComponent), "send_new_enrolment_code_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), ResetSmsCounter: prepareEndpoint(management.MakeResetSmsCounterEndpoint(keycloakComponent), "reset_sms_counter_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), + RecoveryCode: prepareEndpoint(management.MakeRecoveryCodeEndpoint(keycloakComponent), "recovery_code_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), GetCredentialsForUser: prepareEndpoint(management.MakeGetCredentialsForUserEndpoint(keycloakComponent), "get_credentials_for_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), DeleteCredentialsForUser: prepareEndpoint(management.MakeDeleteCredentialsForUserEndpoint(keycloakComponent), "delete_credentials_for_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), GetRealmCustomConfiguration: prepareEndpoint(management.MakeGetRealmCustomConfigurationEndpoint(keycloakComponent), "get_realm_custom_config_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), @@ -649,6 +650,7 @@ func main() { var sendNewEnrolmentCodeHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendNewEnrolmentCode) var sendReminderEmailHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendReminderEmail) var resetSmsCounterHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.ResetSmsCounter) + var recoveryCodeHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.RecoveryCode) var getCredentialsForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetCredentialsForUser) var deleteCredentialsForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.DeleteCredentialsForUser) @@ -687,6 +689,7 @@ func main() { managementSubroute.Path("/realms/{realm}/users/{userID}/send-new-enrolment-code").Methods("POST").Handler(sendNewEnrolmentCodeHandler) managementSubroute.Path("/realms/{realm}/users/{userID}/send-reminder-email").Methods("POST").Handler(sendReminderEmailHandler) managementSubroute.Path("/realms/{realm}/users/{userID}/reset-sms-counter").Methods("PUT").Handler(resetSmsCounterHandler) + managementSubroute.Path("/realms/{realm}/users/{userID}/recovery-code").Methods("POST").Handler(recoveryCodeHandler) // Credentials managementSubroute.Path("/realms/{realm}/users/{userID}/credentials").Methods("GET").Handler(getCredentialsForUserHandler) diff --git a/pkg/management/authorization.go b/pkg/management/authorization.go index 75479bd1e..fb1077e5e 100644 --- a/pkg/management/authorization.go +++ b/pkg/management/authorization.go @@ -31,6 +31,7 @@ const ( SendNewEnrolmentCode = "SendNewEnrolmentCode" SendReminderEmail = "SendReminderEmail" ResetSmsCounter = "ResetSmsCounter" + RecoveryCode = "RecoveryCode" GetCredentialsForUser = "GetCredentialsForUser" DeleteCredentialsForUser = "DeleteCredentialsForUser" GetRoles = "GetRoles" @@ -241,6 +242,17 @@ func (c *authorizationComponentMW) ResetPassword(ctx context.Context, realmName return c.next.ResetPassword(ctx, realmName, userID, password) } +func (c *authorizationComponentMW) RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) { + var action = RecoveryCode + var targetRealm = realmName + + if err := c.authManager.CheckAuthorizationOnTargetUser(ctx, action, targetRealm, userID); err != nil { + return "", err + } + + return c.next.RecoveryCode(ctx, realmName, userID) +} + func (c *authorizationComponentMW) SendVerifyEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error { var action = SendVerifyEmail var targetRealm = realmName diff --git a/pkg/management/authorization_test.go b/pkg/management/authorization_test.go index 88295d52e..b483394d4 100644 --- a/pkg/management/authorization_test.go +++ b/pkg/management/authorization_test.go @@ -142,6 +142,9 @@ func TestDeny(t *testing.T) { err = authorizationMW.ResetSmsCounter(ctx, realmName, userID) assert.Equal(t, security.ForbiddenError{}, err) + _, err = authorizationMW.RecoveryCode(ctx, realmName, userID) + assert.Equal(t, security.ForbiddenError{}, err) + _, err = authorizationMW.GetCredentialsForUser(ctx, realmName, userID) assert.Equal(t, security.ForbiddenError{}, err) @@ -247,6 +250,7 @@ func TestAllowed(t *testing.T) { "SendNewEnrolmentCode": {"*": {"*": {} }}, "SendReminderEmail": {"*": {"*": {} }}, "ResetSmsCounter": {"*": {"*": {} }}, + "RecoveryCode": {"*": {"*": {} }}, "GetCredentialsForUser": {"*": {"*": {} }}, "DeleteCredentialsForUser": {"*": {"*": {} }}, "GetRoles": {"*": {"*": {} }}, @@ -353,6 +357,11 @@ func TestAllowed(t *testing.T) { err = authorizationMW.ResetSmsCounter(ctx, realmName, userID) assert.Nil(t, err) + mockManagementComponent.EXPECT().RecoveryCode(ctx, realmName, userID).Return("123456", nil).Times(1) + code, err := authorizationMW.RecoveryCode(ctx, realmName, userID) + assert.Nil(t, err) + assert.NotNil(t, code) + mockManagementComponent.EXPECT().GetCredentialsForUser(ctx, realmName, userID).Return([]api.CredentialRepresentation{}, nil).Times(1) _, err = authorizationMW.GetCredentialsForUser(ctx, realmName, userID) assert.Nil(t, err) diff --git a/pkg/management/component.go b/pkg/management/component.go index 7002637eb..813b2c263 100644 --- a/pkg/management/component.go +++ b/pkg/management/component.go @@ -40,6 +40,7 @@ type KeycloakClient interface { SendVerifyEmail(accessToken string, realmName string, userID string, paramKV ...string) error ExecuteActionsEmail(accessToken string, realmName string, userID string, actions []string, paramKV ...string) error SendNewEnrolmentCode(accessToken string, realmName string, userID string) (kc.SmsCodeRepresentation, error) + CreateRecoveryCode(accessToken string, realmName string, userID string) (kc.RecoveryCodeRepresentation, error) SendReminderEmail(accessToken string, realmName string, userID string, paramKV ...string) error GetRoles(accessToken string, realmName string) ([]kc.RoleRepresentation, error) GetRole(accessToken string, realmName string, roleID string) (kc.RoleRepresentation, error) @@ -81,6 +82,7 @@ type Component interface { SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error ResetSmsCounter(ctx context.Context, realmName string, userID string) error + RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) DeleteCredentialsForUser(ctx context.Context, realmName string, userID string, credentialID string) error GetRoles(ctx context.Context, realmName string) ([]api.RoleRepresentation, error) @@ -661,6 +663,22 @@ func (c *component) ResetSmsCounter(ctx context.Context, realmName, userID strin return nil } +func (c *component) RecoveryCode(ctx context.Context, realmName, userID string) (string, error) { + var accessToken = ctx.Value(cs.CtContextAccessToken).(string) + + recoveryCodeKc, err := c.keycloakClient.CreateRecoveryCode(accessToken, realmName, userID) + + if err != nil { + c.logger.Warn(ctx, "err", err.Error()) + return "", err + } + + // store the API call into the DB + c.reportEvent(ctx, "RECOVERY_CODE", database.CtEventRealmName, realmName, database.CtEventUserID, userID) + + return *recoveryCodeKc.Code, err +} + func (c *component) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) { var accessToken = ctx.Value(cs.CtContextAccessToken).(string) diff --git a/pkg/management/component_test.go b/pkg/management/component_test.go index be096c11d..9c3c00eda 100644 --- a/pkg/management/component_test.go +++ b/pkg/management/component_test.go @@ -1509,6 +1509,79 @@ func TestResetPassword(t *testing.T) { } +func TestRecoveryCode(t *testing.T) { + var mockCtrl = gomock.NewController(t) + defer mockCtrl.Finish() + var mockKeycloakClient = mock.NewKeycloakClient(mockCtrl) + var mockEventDBModule = mock.NewEventDBModule(mockCtrl) + var mockConfigurationDBModule = mock.NewConfigurationDBModule(mockCtrl) + var mockLogger = mock.NewLogger(mockCtrl) + + var managementComponent = NewComponent(mockKeycloakClient, mockEventDBModule, mockConfigurationDBModule, mockLogger) + + var accessToken = "TOKEN==" + var realmName = "master" + var userID = "41dbf4a8-32a9-4000-8c17-edc854c31231" + var username = "username" + var code = "123456" + + // RecoveryCode + { + var kcCodeRep = kc.RecoveryCodeRepresentation{ + Code: &code, + } + + mockKeycloakClient.EXPECT().CreateRecoveryCode(accessToken, realmName, userID).Return(kcCodeRep, nil).Times(1) + + var ctx = context.WithValue(context.Background(), cs.CtContextAccessToken, accessToken) + ctx = context.WithValue(ctx, cs.CtContextRealm, realmName) + ctx = context.WithValue(ctx, cs.CtContextUsername, username) + + mockEventDBModule.EXPECT().ReportEvent(ctx, "RECOVERY_CODE", "back-office", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) + + recoveryCode, err := managementComponent.RecoveryCode(ctx, "master", userID) + + assert.Nil(t, err) + assert.Equal(t, code, recoveryCode) + } + + // RecoveryCode already exists + { + var err409 = kc.HTTPError{ + HTTPStatus: 409, + Message: "Conflict", + } + var kcCodeRep = kc.RecoveryCodeRepresentation{} + + mockKeycloakClient.EXPECT().CreateRecoveryCode(accessToken, realmName, userID).Return(kcCodeRep, err409).Times(1) + + var ctx = context.WithValue(context.Background(), cs.CtContextAccessToken, accessToken) + ctx = context.WithValue(ctx, cs.CtContextRealm, realmName) + ctx = context.WithValue(ctx, cs.CtContextUsername, username) + + mockLogger.EXPECT().Warn(gomock.Any(), "err", "409:Conflict") + _, err := managementComponent.RecoveryCode(ctx, "master", userID) + + assert.NotNil(t, err) + } + + // Error + { + var kcCodeRep = kc.RecoveryCodeRepresentation{} + mockKeycloakClient.EXPECT().CreateRecoveryCode(accessToken, realmName, userID).Return(kcCodeRep, fmt.Errorf("Error")).Times(1) + + var ctx = context.WithValue(context.Background(), cs.CtContextAccessToken, accessToken) + ctx = context.WithValue(ctx, cs.CtContextRealm, realmName) + ctx = context.WithValue(ctx, cs.CtContextUsername, username) + + mockLogger.EXPECT().Warn(gomock.Any(), "err", "Error") + _, err := managementComponent.RecoveryCode(ctx, "master", userID) + + assert.NotNil(t, err) + } + +} + func TestSendVerifyEmail(t *testing.T) { var mockCtrl = gomock.NewController(t) defer mockCtrl.Finish() diff --git a/pkg/management/endpoint.go b/pkg/management/endpoint.go index a76531bca..420535169 100644 --- a/pkg/management/endpoint.go +++ b/pkg/management/endpoint.go @@ -37,6 +37,7 @@ type Endpoints struct { SendNewEnrolmentCode endpoint.Endpoint SendReminderEmail endpoint.Endpoint ResetSmsCounter endpoint.Endpoint + RecoveryCode endpoint.Endpoint GetCredentialsForUser endpoint.Endpoint DeleteCredentialsForUser endpoint.Endpoint GetRoles endpoint.Endpoint @@ -71,6 +72,7 @@ type ManagementComponent interface { SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error ResetSmsCounter(ctx context.Context, realmName string, userID string) error + RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) DeleteCredentialsForUser(ctx context.Context, realmName string, userID string, credentialID string) error GetRoles(ctx context.Context, realmName string) ([]api.RoleRepresentation, error) @@ -385,6 +387,15 @@ func MakeResetSmsCounterEndpoint(managementComponent ManagementComponent) cs.End } } +// MakeRecoveryCodeEndpoint creates an endpoint for MakeRecoveryCode +func MakeRecoveryCodeEndpoint(managementComponent ManagementComponent) cs.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + var m = req.(map[string]string) + + return managementComponent.RecoveryCode(ctx, m["realm"], m["userID"]) + } +} + // MakeGetCredentialsForUserEndpoint creates an endpoint for GetCredentialsForUser func MakeGetCredentialsForUserEndpoint(managementComponent ManagementComponent) cs.Endpoint { return func(ctx context.Context, req interface{}) (interface{}, error) { diff --git a/pkg/management/endpoint_test.go b/pkg/management/endpoint_test.go index ccfd2173c..bef545c5f 100644 --- a/pkg/management/endpoint_test.go +++ b/pkg/management/endpoint_test.go @@ -686,6 +686,28 @@ func TestResetSmsCounterEndpoint(t *testing.T) { } +func TestRecoveryCodeEndpoint(t *testing.T) { + var mockCtrl = gomock.NewController(t) + defer mockCtrl.Finish() + + var mockManagementComponent = mock.NewManagementComponent(mockCtrl) + + var e = MakeRecoveryCodeEndpoint(mockManagementComponent) + + var realm = "master" + var userID = "123-456-789" + var ctx = context.Background() + var req = make(map[string]string) + req["realm"] = realm + req["userID"] = userID + + mockManagementComponent.EXPECT().RecoveryCode(ctx, realm, userID).Return("123456", nil).Times(1) + var res, err = e(ctx, req) + assert.Nil(t, err) + assert.Equal(t, "123456", res) + +} + func TestGetCredentialsForUserEndpoint(t *testing.T) { var mockCtrl = gomock.NewController(t) defer mockCtrl.Finish() From c89aed8f8feb4b170adcbd2327d18e12110830c1 Mon Sep 17 00:00:00 2001 From: harture Date: Wed, 8 Jan 2020 10:37:23 +0100 Subject: [PATCH 2/3] fixup --- configs/authorization.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configs/authorization.json b/configs/authorization.json index 94d7e0174..298d7f695 100644 --- a/configs/authorization.json +++ b/configs/authorization.json @@ -86,6 +86,13 @@ "l3_support_manager": {} } }, + "RecoveryCode": { + "master": { + "integrator_manager": {}, + "l2_support_manager": {}, + "l3_support_manager": {} + } + }, "GetRequiredActions": { "master": {} }, From 0ce9978ab79cc7856e8d405c7e73976e148092da Mon Sep 17 00:00:00 2001 From: harture Date: Wed, 8 Jan 2020 11:20:42 +0100 Subject: [PATCH 3/3] Renaming --- cmd/keycloakb/keycloak_bridge.go | 6 +++--- pkg/management/authorization.go | 8 ++++---- pkg/management/authorization_test.go | 8 ++++---- pkg/management/component.go | 6 +++--- pkg/management/component_test.go | 8 ++++---- pkg/management/endpoint.go | 10 +++++----- pkg/management/endpoint_test.go | 4 ++-- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/keycloakb/keycloak_bridge.go b/cmd/keycloakb/keycloak_bridge.go index acfa3c133..03e3c1866 100644 --- a/cmd/keycloakb/keycloak_bridge.go +++ b/cmd/keycloakb/keycloak_bridge.go @@ -477,7 +477,7 @@ func main() { SendReminderEmail: prepareEndpoint(management.MakeSendReminderEmailEndpoint(keycloakComponent), "send_reminder_email_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), SendNewEnrolmentCode: prepareEndpoint(management.MakeSendNewEnrolmentCodeEndpoint(keycloakComponent), "send_new_enrolment_code_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), ResetSmsCounter: prepareEndpoint(management.MakeResetSmsCounterEndpoint(keycloakComponent), "reset_sms_counter_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), - RecoveryCode: prepareEndpoint(management.MakeRecoveryCodeEndpoint(keycloakComponent), "recovery_code_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), + CreateRecoveryCode: prepareEndpoint(management.MakeCreateRecoveryCodeEndpoint(keycloakComponent), "create_recovery_code_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), GetCredentialsForUser: prepareEndpoint(management.MakeGetCredentialsForUserEndpoint(keycloakComponent), "get_credentials_for_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), DeleteCredentialsForUser: prepareEndpoint(management.MakeDeleteCredentialsForUserEndpoint(keycloakComponent), "delete_credentials_for_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), GetRealmCustomConfiguration: prepareEndpoint(management.MakeGetRealmCustomConfigurationEndpoint(keycloakComponent), "get_realm_custom_config_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]), @@ -650,7 +650,7 @@ func main() { var sendNewEnrolmentCodeHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendNewEnrolmentCode) var sendReminderEmailHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendReminderEmail) var resetSmsCounterHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.ResetSmsCounter) - var recoveryCodeHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.RecoveryCode) + var createRecoveryCodeHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.CreateRecoveryCode) var getCredentialsForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetCredentialsForUser) var deleteCredentialsForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.DeleteCredentialsForUser) @@ -689,7 +689,7 @@ func main() { managementSubroute.Path("/realms/{realm}/users/{userID}/send-new-enrolment-code").Methods("POST").Handler(sendNewEnrolmentCodeHandler) managementSubroute.Path("/realms/{realm}/users/{userID}/send-reminder-email").Methods("POST").Handler(sendReminderEmailHandler) managementSubroute.Path("/realms/{realm}/users/{userID}/reset-sms-counter").Methods("PUT").Handler(resetSmsCounterHandler) - managementSubroute.Path("/realms/{realm}/users/{userID}/recovery-code").Methods("POST").Handler(recoveryCodeHandler) + managementSubroute.Path("/realms/{realm}/users/{userID}/recovery-code").Methods("POST").Handler(createRecoveryCodeHandler) // Credentials managementSubroute.Path("/realms/{realm}/users/{userID}/credentials").Methods("GET").Handler(getCredentialsForUserHandler) diff --git a/pkg/management/authorization.go b/pkg/management/authorization.go index fb1077e5e..44b8da563 100644 --- a/pkg/management/authorization.go +++ b/pkg/management/authorization.go @@ -31,7 +31,7 @@ const ( SendNewEnrolmentCode = "SendNewEnrolmentCode" SendReminderEmail = "SendReminderEmail" ResetSmsCounter = "ResetSmsCounter" - RecoveryCode = "RecoveryCode" + CreateRecoveryCode = "CreateRecoveryCode" GetCredentialsForUser = "GetCredentialsForUser" DeleteCredentialsForUser = "DeleteCredentialsForUser" GetRoles = "GetRoles" @@ -242,15 +242,15 @@ func (c *authorizationComponentMW) ResetPassword(ctx context.Context, realmName return c.next.ResetPassword(ctx, realmName, userID, password) } -func (c *authorizationComponentMW) RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) { - var action = RecoveryCode +func (c *authorizationComponentMW) CreateRecoveryCode(ctx context.Context, realmName string, userID string) (string, error) { + var action = CreateRecoveryCode var targetRealm = realmName if err := c.authManager.CheckAuthorizationOnTargetUser(ctx, action, targetRealm, userID); err != nil { return "", err } - return c.next.RecoveryCode(ctx, realmName, userID) + return c.next.CreateRecoveryCode(ctx, realmName, userID) } func (c *authorizationComponentMW) SendVerifyEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error { diff --git a/pkg/management/authorization_test.go b/pkg/management/authorization_test.go index b483394d4..69b7a32b0 100644 --- a/pkg/management/authorization_test.go +++ b/pkg/management/authorization_test.go @@ -142,7 +142,7 @@ func TestDeny(t *testing.T) { err = authorizationMW.ResetSmsCounter(ctx, realmName, userID) assert.Equal(t, security.ForbiddenError{}, err) - _, err = authorizationMW.RecoveryCode(ctx, realmName, userID) + _, err = authorizationMW.CreateRecoveryCode(ctx, realmName, userID) assert.Equal(t, security.ForbiddenError{}, err) _, err = authorizationMW.GetCredentialsForUser(ctx, realmName, userID) @@ -250,7 +250,7 @@ func TestAllowed(t *testing.T) { "SendNewEnrolmentCode": {"*": {"*": {} }}, "SendReminderEmail": {"*": {"*": {} }}, "ResetSmsCounter": {"*": {"*": {} }}, - "RecoveryCode": {"*": {"*": {} }}, + "CreateRecoveryCode": {"*": {"*": {} }}, "GetCredentialsForUser": {"*": {"*": {} }}, "DeleteCredentialsForUser": {"*": {"*": {} }}, "GetRoles": {"*": {"*": {} }}, @@ -357,8 +357,8 @@ func TestAllowed(t *testing.T) { err = authorizationMW.ResetSmsCounter(ctx, realmName, userID) assert.Nil(t, err) - mockManagementComponent.EXPECT().RecoveryCode(ctx, realmName, userID).Return("123456", nil).Times(1) - code, err := authorizationMW.RecoveryCode(ctx, realmName, userID) + mockManagementComponent.EXPECT().CreateRecoveryCode(ctx, realmName, userID).Return("123456", nil).Times(1) + code, err := authorizationMW.CreateRecoveryCode(ctx, realmName, userID) assert.Nil(t, err) assert.NotNil(t, code) diff --git a/pkg/management/component.go b/pkg/management/component.go index 813b2c263..66456dac2 100644 --- a/pkg/management/component.go +++ b/pkg/management/component.go @@ -82,7 +82,7 @@ type Component interface { SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error ResetSmsCounter(ctx context.Context, realmName string, userID string) error - RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) + CreateRecoveryCode(ctx context.Context, realmName string, userID string) (string, error) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) DeleteCredentialsForUser(ctx context.Context, realmName string, userID string, credentialID string) error GetRoles(ctx context.Context, realmName string) ([]api.RoleRepresentation, error) @@ -663,7 +663,7 @@ func (c *component) ResetSmsCounter(ctx context.Context, realmName, userID strin return nil } -func (c *component) RecoveryCode(ctx context.Context, realmName, userID string) (string, error) { +func (c *component) CreateRecoveryCode(ctx context.Context, realmName, userID string) (string, error) { var accessToken = ctx.Value(cs.CtContextAccessToken).(string) recoveryCodeKc, err := c.keycloakClient.CreateRecoveryCode(accessToken, realmName, userID) @@ -674,7 +674,7 @@ func (c *component) RecoveryCode(ctx context.Context, realmName, userID string) } // store the API call into the DB - c.reportEvent(ctx, "RECOVERY_CODE", database.CtEventRealmName, realmName, database.CtEventUserID, userID) + c.reportEvent(ctx, "CREATE_RECOVERY_CODE", database.CtEventRealmName, realmName, database.CtEventUserID, userID) return *recoveryCodeKc.Code, err } diff --git a/pkg/management/component_test.go b/pkg/management/component_test.go index 9c3c00eda..ca7a5af44 100644 --- a/pkg/management/component_test.go +++ b/pkg/management/component_test.go @@ -1537,9 +1537,9 @@ func TestRecoveryCode(t *testing.T) { ctx = context.WithValue(ctx, cs.CtContextRealm, realmName) ctx = context.WithValue(ctx, cs.CtContextUsername, username) - mockEventDBModule.EXPECT().ReportEvent(ctx, "RECOVERY_CODE", "back-office", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) + mockEventDBModule.EXPECT().ReportEvent(ctx, "CREATE_RECOVERY_CODE", "back-office", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) - recoveryCode, err := managementComponent.RecoveryCode(ctx, "master", userID) + recoveryCode, err := managementComponent.CreateRecoveryCode(ctx, "master", userID) assert.Nil(t, err) assert.Equal(t, code, recoveryCode) @@ -1560,7 +1560,7 @@ func TestRecoveryCode(t *testing.T) { ctx = context.WithValue(ctx, cs.CtContextUsername, username) mockLogger.EXPECT().Warn(gomock.Any(), "err", "409:Conflict") - _, err := managementComponent.RecoveryCode(ctx, "master", userID) + _, err := managementComponent.CreateRecoveryCode(ctx, "master", userID) assert.NotNil(t, err) } @@ -1575,7 +1575,7 @@ func TestRecoveryCode(t *testing.T) { ctx = context.WithValue(ctx, cs.CtContextUsername, username) mockLogger.EXPECT().Warn(gomock.Any(), "err", "Error") - _, err := managementComponent.RecoveryCode(ctx, "master", userID) + _, err := managementComponent.CreateRecoveryCode(ctx, "master", userID) assert.NotNil(t, err) } diff --git a/pkg/management/endpoint.go b/pkg/management/endpoint.go index 420535169..1957d572c 100644 --- a/pkg/management/endpoint.go +++ b/pkg/management/endpoint.go @@ -37,7 +37,7 @@ type Endpoints struct { SendNewEnrolmentCode endpoint.Endpoint SendReminderEmail endpoint.Endpoint ResetSmsCounter endpoint.Endpoint - RecoveryCode endpoint.Endpoint + CreateRecoveryCode endpoint.Endpoint GetCredentialsForUser endpoint.Endpoint DeleteCredentialsForUser endpoint.Endpoint GetRoles endpoint.Endpoint @@ -72,7 +72,7 @@ type ManagementComponent interface { SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error ResetSmsCounter(ctx context.Context, realmName string, userID string) error - RecoveryCode(ctx context.Context, realmName string, userID string) (string, error) + CreateRecoveryCode(ctx context.Context, realmName string, userID string) (string, error) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) DeleteCredentialsForUser(ctx context.Context, realmName string, userID string, credentialID string) error GetRoles(ctx context.Context, realmName string) ([]api.RoleRepresentation, error) @@ -387,12 +387,12 @@ func MakeResetSmsCounterEndpoint(managementComponent ManagementComponent) cs.End } } -// MakeRecoveryCodeEndpoint creates an endpoint for MakeRecoveryCode -func MakeRecoveryCodeEndpoint(managementComponent ManagementComponent) cs.Endpoint { +// MakeCreateRecoveryCodeEndpoint creates an endpoint for MakeCreateRecoveryCode +func MakeCreateRecoveryCodeEndpoint(managementComponent ManagementComponent) cs.Endpoint { return func(ctx context.Context, req interface{}) (interface{}, error) { var m = req.(map[string]string) - return managementComponent.RecoveryCode(ctx, m["realm"], m["userID"]) + return managementComponent.CreateRecoveryCode(ctx, m["realm"], m["userID"]) } } diff --git a/pkg/management/endpoint_test.go b/pkg/management/endpoint_test.go index bef545c5f..bffd11714 100644 --- a/pkg/management/endpoint_test.go +++ b/pkg/management/endpoint_test.go @@ -692,7 +692,7 @@ func TestRecoveryCodeEndpoint(t *testing.T) { var mockManagementComponent = mock.NewManagementComponent(mockCtrl) - var e = MakeRecoveryCodeEndpoint(mockManagementComponent) + var e = MakeCreateRecoveryCodeEndpoint(mockManagementComponent) var realm = "master" var userID = "123-456-789" @@ -701,7 +701,7 @@ func TestRecoveryCodeEndpoint(t *testing.T) { req["realm"] = realm req["userID"] = userID - mockManagementComponent.EXPECT().RecoveryCode(ctx, realm, userID).Return("123456", nil).Times(1) + mockManagementComponent.EXPECT().CreateRecoveryCode(ctx, realm, userID).Return("123456", nil).Times(1) var res, err = e(ctx, req) assert.Nil(t, err) assert.Equal(t, "123456", res)