Skip to content

Commit

Permalink
CLOUDTRUST-1392 Send reminder email API
Browse files Browse the repository at this point in the history
  • Loading branch information
bsoniam authored and harture committed Jul 1, 2019
1 parent d0749b2 commit 2ca9cf0
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 0 deletions.
3 changes: 3 additions & 0 deletions cmd/keycloakb/keycloak_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ func main() {
ResetPassword: prepareEndpoint(management.MakeResetPasswordEndpoint(keycloakComponent), "reset_password_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
SendVerifyEmail: prepareEndpoint(management.MakeSendVerifyEmailEndpoint(keycloakComponent), "send_verify_email_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
ExecuteActionsEmail: prepareEndpoint(management.MakeExecuteActionsEmailEndpoint(keycloakComponent), "execute_actions_email_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
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"]),
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"]),
Expand Down Expand Up @@ -535,6 +536,7 @@ func main() {
var sendVerifyEmailHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendVerifyEmail)
var executeActionsEmailHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.ExecuteActionsEmail)
var sendNewEnrolmentCodeHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendNewEnrolmentCode)
var sendReminderEmailHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SendReminderEmail)

var getCredentialsForUserHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetCredentialsForUser)
var deleteCredentialsForUserHandler = configureManagementHandler(ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.DeleteCredentialsForUser)
Expand Down Expand Up @@ -568,6 +570,7 @@ func main() {
managementSubroute.Path("/realms/{realm}/users/{userID}/send-verify-email").Methods("PUT").Handler(sendVerifyEmailHandler)
managementSubroute.Path("/realms/{realm}/users/{userID}/execute-actions-email").Methods("PUT").Handler(executeActionsEmailHandler)
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)

// Credentials
managementSubroute.Path("/realms/{realm}/users/{userID}/credentials").Methods("GET").Handler(getCredentialsForUserHandler)
Expand Down
51 changes: 51 additions & 0 deletions configs/authorization.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
"l3_support_manager": {}
}
},
"SendReminderEmail": {
"master": {
"integrator_manager": {},
"l2_support_manager": {},
"l3_support_manager": {}
}
},
"GetCredentialsForUser": {
"master": {
"*": {}
Expand Down Expand Up @@ -210,6 +217,14 @@
"end_user": {}
}
},
"SendReminderEmail": {
"master": {
"integrator_agent": {}
},
"DEP": {
"end_user": {}
}
},
"GetCredentialsForUser": {
"master": {
"integrator_agent": {}
Expand Down Expand Up @@ -322,6 +337,11 @@
"*": {}
}
},
"SendReminderEmail": {
"DEP": {
"*": {}
}
},
"GetCredentialsForUser": {
"DEP": {
"*": {}
Expand Down Expand Up @@ -425,6 +445,11 @@
"l2_support_agent": {}
}
},
"SendReminderEmail": {
"master": {
"l2_support_agent": {}
}
},
"GetCredentialsForUser": {
"master": {
"l2_support_agent": {}
Expand Down Expand Up @@ -540,6 +565,11 @@
"l3_support_agent": {}
}
},
"SendReminderEmail": {
"master": {
"l3_support_agent": {}
}
},
"GetCredentialsForUser": {
"master": {
"l3_support_agent": {}
Expand Down Expand Up @@ -658,6 +688,11 @@
"*": {}
}
},
"SendReminderEmail": {
"DEP": {
"*": {}
}
},
"SendNewEnrolmentCode":{
"DEP": {
"end_user": {}
Expand Down Expand Up @@ -770,6 +805,12 @@
"end_user": {}
}
},
"SendReminderEmail": {
"DEP": {
"l1_support_agent": {},
"end_user": {}
}
},
"GetCredentialsForUser": {
"DEP": {
"l1_support_agent": {},
Expand Down Expand Up @@ -850,6 +891,11 @@
"end_user": {}
}
},
"SendReminderEmail": {
"DEP": {
"end_user": {}
}
},
"GetCredentialsForUser": {
"DEP": {
"end_user": {}
Expand Down Expand Up @@ -882,6 +928,11 @@
"end_user": {}
}
},
"SendReminderEmail": {
"DEP": {
"end_user": {}
}
},
"GetGroups": {
"DEP": {
"*": {}
Expand Down
12 changes: 12 additions & 0 deletions pkg/management/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
SendVerifyEmail = "SendVerifyEmail"
ExecuteActionsEmail = "ExecuteActionsEmail"
SendNewEnrolmentCode = "SendNewEnrolmentCode"
SendReminderEmail = "SendReminderEmail"
GetCredentialsForUser = "GetCredentialsForUser"
DeleteCredentialsForUser = "DeleteCredentialsForUser"
GetRoles = "GetRoles"
Expand Down Expand Up @@ -260,6 +261,17 @@ func (c *authorizationComponentMW) SendNewEnrolmentCode(ctx context.Context, rea
return c.next.SendNewEnrolmentCode(ctx, realmName, userID)
}

func (c *authorizationComponentMW) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error {
var action = SendReminderEmail
var targetRealm = realmName

if err := c.authManager.CheckAuthorizationOnTargetUser(ctx, action, targetRealm, userID); err != nil {
return err
}

return c.next.SendReminderEmail(ctx, realmName, userID, paramKV...)
}

func (c *authorizationComponentMW) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) {
var action = GetCredentialsForUser
var targetRealm = realmName
Expand Down
8 changes: 8 additions & 0 deletions pkg/management/authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ func TestDeny(t *testing.T) {
_, err = authorizationMW.SendNewEnrolmentCode(ctx, realmName, userID)
assert.Equal(t, security.ForbiddenError{}, err)

err = authorizationMW.SendReminderEmail(ctx, realmName, userID)
assert.Equal(t, security.ForbiddenError{}, err)

_, err = authorizationMW.GetCredentialsForUser(ctx, realmName, userID)
assert.Equal(t, security.ForbiddenError{}, err)

Expand Down Expand Up @@ -235,6 +238,7 @@ func TestAllowed(t *testing.T) {
"SendVerifyEmail": {"*": {"*": {} }},
"ExecuteActionsEmail": {"*": {"*": {} }},
"SendNewEnrolmentCode": {"*": {"*": {} }},
"SendReminderEmail": {"*": {"*": {} }},
"GetCredentialsForUser": {"*": {"*": {} }},
"DeleteCredentialsForUser": {"*": {"*": {} }},
"GetRoles": {"*": {"*": {} }},
Expand Down Expand Up @@ -329,6 +333,10 @@ func TestAllowed(t *testing.T) {
_, err = authorizationMW.SendNewEnrolmentCode(ctx, realmName, userID)
assert.Nil(t, err)

mockManagementComponent.EXPECT().SendReminderEmail(ctx, realmName, userID).Return(nil).Times(1)
err = authorizationMW.SendReminderEmail(ctx, realmName, userID)
assert.Nil(t, err)

mockManagementComponent.EXPECT().GetCredentialsForUser(ctx, realmName, userID).Return([]api.CredentialRepresentation{}, nil).Times(1)
_, err = authorizationMW.GetCredentialsForUser(ctx, realmName, userID)
assert.Nil(t, err)
Expand Down
8 changes: 8 additions & 0 deletions pkg/management/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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)
SendReminderEmail(accessToken string, realmName string, userID string, paramKV ...string) error
GetCredentialsForUser(accessToken string, realmReq, realmName string, userID string) ([]kc.CredentialRepresentation, error)
DeleteCredentialsForUser(accessToken string, realmReq, realmName string, userID string, credentialID string) error
GetRoles(accessToken string, realmName string) ([]kc.RoleRepresentation, error)
Expand Down Expand Up @@ -62,6 +63,7 @@ type Component interface {
SendVerifyEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error
ExecuteActionsEmail(ctx context.Context, realmName string, userID string, actions []api.RequiredAction, paramKV ...string) error
SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error)
SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...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)
Expand Down Expand Up @@ -513,6 +515,12 @@ func (c *component) SendNewEnrolmentCode(ctx context.Context, realmName string,
return *smsCodeKc.Code, err
}

func (c *component) SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error {
var accessToken = ctx.Value(cs.CtContextAccessToken).(string)

return c.keycloakClient.SendReminderEmail(accessToken, realmName, userID, paramKV...)
}

func (c *component) GetCredentialsForUser(ctx context.Context, realmName string, userID string) ([]api.CredentialRepresentation, error) {
var accessToken = ctx.Value(cs.CtContextAccessToken).(string)
var ctxRealm = ctx.Value(cs.CtContextRealm).(string)
Expand Down
44 changes: 44 additions & 0 deletions pkg/management/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,50 @@ func TestSendNewEnrolmentCode(t *testing.T) {
}
}

func TestSendReminderEmail(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 managementComponent = NewComponent(mockKeycloakClient, mockEventDBModule, mockConfigurationDBModule)

var accessToken = "TOKEN=="
var realmName = "master"
var userID = "1245-7854-8963"

var key1 = "key1"
var value1 = "value1"
var key2 = "key2"
var value2 = "value2"
var key3 = "key3"
var value3 = "value3"

// Send email
{

mockKeycloakClient.EXPECT().SendReminderEmail(accessToken, realmName, userID, key1, value1, key2, value2, key3, value3).Return(nil).Times(1)

var ctx = context.WithValue(context.Background(), cs.CtContextAccessToken, accessToken)

err := managementComponent.SendReminderEmail(ctx, "master", userID, key1, value1, key2, value2, key3, value3)

assert.Nil(t, err)
}

// Error
{
mockKeycloakClient.EXPECT().SendReminderEmail(accessToken, realmName, userID).Return(fmt.Errorf("Invalid input")).Times(1)

var ctx = context.WithValue(context.Background(), cs.CtContextAccessToken, accessToken)

err := managementComponent.SendReminderEmail(ctx, "master", userID)

assert.NotNil(t, err)
}
}

func TestGetCredentialsForUser(t *testing.T) {
var mockCtrl = gomock.NewController(t)
defer mockCtrl.Finish()
Expand Down
18 changes: 18 additions & 0 deletions pkg/management/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Endpoints struct {
SendVerifyEmail endpoint.Endpoint
ExecuteActionsEmail endpoint.Endpoint
SendNewEnrolmentCode endpoint.Endpoint
SendReminderEmail endpoint.Endpoint
GetCredentialsForUser endpoint.Endpoint
DeleteCredentialsForUser endpoint.Endpoint
GetRoles endpoint.Endpoint
Expand Down Expand Up @@ -64,6 +65,7 @@ type ManagementComponent interface {
SendVerifyEmail(ctx context.Context, realmName string, userID string, paramKV ...string) error
ExecuteActionsEmail(ctx context.Context, realmName string, userID string, actions []api.RequiredAction, paramKV ...string) error
SendNewEnrolmentCode(ctx context.Context, realmName string, userID string) (string, error)
SendReminderEmail(ctx context.Context, realmName string, userID string, paramKV ...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)
Expand Down Expand Up @@ -339,6 +341,22 @@ func MakeSendNewEnrolmentCodeEndpoint(managementComponent ManagementComponent) c
}
}

// MakeSendReminderEmailEndpoint creates an endpoint for SendReminderEmail
func MakeSendReminderEmailEndpoint(managementComponent ManagementComponent) cs.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
var m = req.(map[string]string)

var paramKV []string
for _, key := range []string{"client_id", "redirect_uri", "lifespan"} {
if m[key] != "" {
paramKV = append(paramKV, key, m[key])
}
}

return nil, managementComponent.SendReminderEmail(ctx, m["realm"], m["userID"], paramKV...)
}
}

// MakeGetCredentialsForUserEndpoint creates an endpoint for GetCredentialsForUser
func MakeGetCredentialsForUserEndpoint(managementComponent ManagementComponent) cs.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
Expand Down
46 changes: 46 additions & 0 deletions pkg/management/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ func TestSendVerifyEmailEndpoint(t *testing.T) {
var res, err = e(ctx, req)
assert.Nil(t, err)
assert.Nil(t, res)

}
}

Expand Down Expand Up @@ -599,6 +600,51 @@ func TestSendNewEnrolmentCodeEndpoint(t *testing.T) {

}

func TestSendReminderEmailEndpoint(t *testing.T) {
var mockCtrl = gomock.NewController(t)
defer mockCtrl.Finish()

var mockManagementComponent = mock.NewManagementComponent(mockCtrl)

var e = MakeSendReminderEmailEndpoint(mockManagementComponent)

// No error - Without param
{
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().SendReminderEmail(ctx, realm, userID).Return(nil).Times(1)
var res, err = e(ctx, req)
assert.Nil(t, err)
assert.Nil(t, res)
}

// No error - With params
{
var realm = "master"
var userID = "123-456-789"
var ctx = context.Background()
var req = make(map[string]string)
var lifespan = 3600
req["realm"] = realm
req["userID"] = userID
req["client_id"] = "123789"
req["redirect_uri"] = "http://redirect.com"
req["lifespan"] = string(lifespan)
req["toto"] = "tutu" // Check this param is not transmitted

mockManagementComponent.EXPECT().SendReminderEmail(ctx, realm, userID, "client_id", req["client_id"], "redirect_uri", req["redirect_uri"], "lifespan", req["lifespan"]).Return(nil).Times(1)
var res, err = e(ctx, req)
assert.Nil(t, err)
assert.Nil(t, res)
// the mock does not except to be called with req["toto"]; as the test passes it means that e has filtered out req["tutu"] and it is not transmitted to SendReminderEmail
}
}

func TestGetCredentialsForUserEndpoint(t *testing.T) {
var mockCtrl = gomock.NewController(t)
defer mockCtrl.Finish()
Expand Down

0 comments on commit 2ca9cf0

Please sign in to comment.