Skip to content

Commit

Permalink
Merge 514ac71 into 4c31fd7
Browse files Browse the repository at this point in the history
  • Loading branch information
fperot74 committed Mar 20, 2020
2 parents 4c31fd7 + 514ac71 commit 896fc30
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 30 deletions.
53 changes: 52 additions & 1 deletion api/management/swagger-api_management.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,29 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Client'
/realms/{realm}/trustIdGroups:
get:
tags:
- Users
summary: Get available trustID groups
parameters:
- name: realm
in: path
description: realm name (not id!)
required: true
schema:
type: string
responses:
200:
description: successful operation
content:
application/json:
schema:
type: array
items:
type: string
example:
["product_administrator","registration_officer"]
/realms/{realm}/users:
post:
tags:
Expand Down Expand Up @@ -361,6 +384,34 @@ paths:
items:
$ref: '#/components/schemas/Group'
/realms/{realm}/users/{userID}/trustIdGroups:
get:
tags:
- Users
summary: Get the trustID groups 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:
200:
description: successful operation
content:
application/json:
schema:
type: array
items:
type: string
example:
["product_administrator","registration_officer"]
put:
tags:
- Users
Expand Down Expand Up @@ -1213,7 +1264,7 @@ components:
type: string
description: expiry date. format is DD.MM.YYYY
expired:
type: bool
type: boolean
description: true if the expiry date has passed
UserStatus:
type: object
Expand Down
26 changes: 17 additions & 9 deletions cmd/keycloakb/keycloak_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,15 +556,17 @@ func main() {
GetClient: prepareEndpoint(management.MakeGetClientEndpoint(keycloakComponent), "get_client_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetRequiredActions: prepareEndpoint(management.MakeGetRequiredActionsEndpoint(keycloakComponent), "get_required-actions_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),

CreateUser: prepareEndpoint(management.MakeCreateUserEndpoint(keycloakComponent), "create_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUser: prepareEndpoint(management.MakeGetUserEndpoint(keycloakComponent), "get_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
UpdateUser: prepareEndpoint(management.MakeUpdateUserEndpoint(keycloakComponent), "update_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
DeleteUser: prepareEndpoint(management.MakeDeleteUserEndpoint(keycloakComponent), "delete_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUsers: prepareEndpoint(management.MakeGetUsersEndpoint(keycloakComponent), "get_users_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUserAccountStatus: prepareEndpoint(management.MakeGetUserAccountStatusEndpoint(keycloakComponent), "get_user_accountstatus", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetGroupsOfUser: prepareEndpoint(management.MakeGetGroupsOfUserEndpoint(keycloakComponent), "get_user_groups", influxMetrics, managementLogger, tracer, rateLimit["management"]),
SetTrustIDGroups: prepareEndpoint(management.MakeSetTrustIDGroupsEndpoint(keycloakComponent), "set_trustid_groups_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetRolesOfUser: prepareEndpoint(management.MakeGetRolesOfUserEndpoint(keycloakComponent), "get_user_roles", influxMetrics, managementLogger, tracer, rateLimit["management"]),
CreateUser: prepareEndpoint(management.MakeCreateUserEndpoint(keycloakComponent), "create_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUser: prepareEndpoint(management.MakeGetUserEndpoint(keycloakComponent), "get_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
UpdateUser: prepareEndpoint(management.MakeUpdateUserEndpoint(keycloakComponent), "update_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
DeleteUser: prepareEndpoint(management.MakeDeleteUserEndpoint(keycloakComponent), "delete_user_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUsers: prepareEndpoint(management.MakeGetUsersEndpoint(keycloakComponent), "get_users_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetUserAccountStatus: prepareEndpoint(management.MakeGetUserAccountStatusEndpoint(keycloakComponent), "get_user_accountstatus", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetGroupsOfUser: prepareEndpoint(management.MakeGetGroupsOfUserEndpoint(keycloakComponent), "get_user_groups", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetAvailableTrustIDGroups: prepareEndpoint(management.MakeGetAvailableTrustIDGroupsEndpoint(keycloakComponent), "get_available_trustid_groups_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetTrustIDGroups: prepareEndpoint(management.MakeGetTrustIDGroupsEndpoint(keycloakComponent), "get_trustid_groups_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
SetTrustIDGroups: prepareEndpoint(management.MakeSetTrustIDGroupsEndpoint(keycloakComponent), "set_trustid_groups_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetRolesOfUser: prepareEndpoint(management.MakeGetRolesOfUserEndpoint(keycloakComponent), "get_user_roles", influxMetrics, managementLogger, tracer, rateLimit["management"]),

GetRoles: prepareEndpoint(management.MakeGetRolesEndpoint(keycloakComponent), "get_roles_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
GetRole: prepareEndpoint(management.MakeGetRoleEndpoint(keycloakComponent), "get_role_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
Expand Down Expand Up @@ -830,6 +832,8 @@ func main() {
var getRolesForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetRolesOfUser)
var getGroupsForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetGroupsOfUser)
var getUserAccountStatusHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetUserAccountStatus)
var getAvailableTrustIDGroupsHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetAvailableTrustIDGroups)
var getTrustIDGroupsHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetTrustIDGroups)
var setTrustIDGroupsHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.SetTrustIDGroups)

var getClientRoleForUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.GetClientRoleForUser)
Expand Down Expand Up @@ -889,6 +893,9 @@ func main() {
// required-actions
managementSubroute.Path("/realms/{realm}/required-actions").Methods("GET").Handler(getRequiredActionsHandler)

// available trust id groups
managementSubroute.Path("/realms/{realm}/trustIdGroups").Methods("GET").Handler(getAvailableTrustIDGroupsHandler)

// users
managementSubroute.Path("/realms/{realm}/users").Methods("GET").Handler(getUsersHandler)
managementSubroute.Path("/realms/{realm}/users").Methods("POST").Handler(createUserHandler)
Expand All @@ -898,6 +905,7 @@ func main() {
managementSubroute.Path("/realms/{realm}/users/{userID}/groups").Methods("GET").Handler(getGroupsForUserHandler)
managementSubroute.Path("/realms/{realm}/users/{userID}/roles").Methods("GET").Handler(getRolesForUserHandler)
managementSubroute.Path("/realms/{realm}/users/{userID}/status").Methods("GET").Handler(getUserAccountStatusHandler)
managementSubroute.Path("/realms/{realm}/users/{userID}/trustIdGroups").Methods("GET").Handler(getTrustIDGroupsHandler)
managementSubroute.Path("/realms/{realm}/users/{userID}/trustIdGroups").Methods("PUT").Handler(setTrustIDGroupsHandler)

// role mappings
Expand Down
24 changes: 24 additions & 0 deletions pkg/management/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ var (
MGMTGetUserAccountStatus = newAction("MGMT_GetUserAccountStatus", security.ScopeGroup)
MGMTGetRolesOfUser = newAction("MGMT_GetRolesOfUser", security.ScopeGroup)
MGMTGetGroupsOfUser = newAction("MGMT_GetGroupsOfUser", security.ScopeGroup)
MGMTGetAvailableTrustIDGroups = newAction("MGMT_GetAvailableTrustIDGroups", security.ScopeRealm)
MGMTGetTrustIDGroups = newAction("MGMT_GetTrustIDGroups", security.ScopeGroup)
MGMTSetTrustIDGroups = newAction("MGMT_SetTrustIDGroups", security.ScopeGroup)
MGMTGetClientRolesForUser = newAction("MGMT_GetClientRolesForUser", security.ScopeGroup)
MGMTAddClientRolesToUser = newAction("MGMT_AddClientRolesToUser", security.ScopeGroup)
Expand Down Expand Up @@ -251,6 +253,28 @@ func (c *authorizationComponentMW) GetGroupsOfUser(ctx context.Context, realmNam
return c.next.GetGroupsOfUser(ctx, realmName, userID)
}

func (c *authorizationComponentMW) GetAvailableTrustIDGroups(ctx context.Context, realmName string) ([]string, error) {
var action = MGMTGetAvailableTrustIDGroups.String()
var targetRealm = realmName

if err := c.authManager.CheckAuthorizationOnTargetRealm(ctx, action, targetRealm); err != nil {
return []string{}, err
}

return c.next.GetAvailableTrustIDGroups(ctx, realmName)
}

func (c *authorizationComponentMW) GetTrustIDGroups(ctx context.Context, realmName, userID string) ([]string, error) {
var action = MGMTGetTrustIDGroups.String()
var targetRealm = realmName

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

return c.next.GetTrustIDGroups(ctx, realmName, userID)
}

func (c *authorizationComponentMW) SetTrustIDGroups(ctx context.Context, realmName, userID string, groupNames []string) error {
var action = MGMTSetTrustIDGroups.String()
var targetRealm = realmName
Expand Down
14 changes: 14 additions & 0 deletions pkg/management/authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ func TestDeny(t *testing.T) {
_, err = authorizationMW.GetGroupsOfUser(ctx, realmName, userID)
assert.Equal(t, security.ForbiddenError{}, err)

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

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

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

Expand Down Expand Up @@ -450,6 +456,14 @@ func TestAllowed(t *testing.T) {
_, err = authorizationMW.GetGroups(ctx, realmName)
assert.Nil(t, err)

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

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

mockManagementComponent.EXPECT().SetTrustIDGroups(ctx, realmName, userID, grpNames).Return(nil).Times(1)
err = authorizationMW.SetTrustIDGroups(ctx, realmName, userID, grpNames)
assert.Nil(t, err)
Expand Down
34 changes: 31 additions & 3 deletions pkg/management/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type Component interface {
GetUserAccountStatus(ctx context.Context, realmName, userID string) (map[string]bool, error)
GetRolesOfUser(ctx context.Context, realmName, userID string) ([]api.RoleRepresentation, error)
GetGroupsOfUser(ctx context.Context, realmName, userID string) ([]api.GroupRepresentation, error)
GetAvailableTrustIDGroups(ctx context.Context, realmName string) ([]string, error)
GetTrustIDGroups(ctx context.Context, realmName, userID string) ([]string, error)
SetTrustIDGroups(ctx context.Context, realmName, userID string, groupNames []string) error
GetClientRolesForUser(ctx context.Context, realmName, userID, clientID string) ([]api.RoleRepresentation, error)
AddClientRolesToUser(ctx context.Context, realmName, userID, clientID string, roles []api.RoleRepresentation) error
Expand Down Expand Up @@ -506,6 +508,32 @@ func (c *component) GetGroupsOfUser(ctx context.Context, realmName, userID strin
return groupsRep, nil
}

func (c *component) GetAvailableTrustIDGroups(ctx context.Context, realmName string) ([]string, error) {
var res []string
for key := range c.authorizedTrustIDGroups {
res = append(res, key)
}
return res, nil
}

func (c *component) GetTrustIDGroups(ctx context.Context, realmName, userID string) ([]string, error) {
var accessToken = ctx.Value(cs.CtContextAccessToken).(string)
var currentUser, err = c.keycloakClient.GetUser(accessToken, realmName, userID)
if err != nil {
c.logger.Warn(ctx, "err", err.Error())
return nil, err
}
var groups = make([]string, 0)
for _, grp := range currentUser.GetAttribute(constants.AttrbTrustIDGroups) {
if strings.HasPrefix(grp, "/") {
grp = grp[1:]
}
groups = append(groups, grp)
}

return groups, nil
}

func (c *component) SetTrustIDGroups(ctx context.Context, realmName, userID string, groupNames []string) error {
var accessToken = ctx.Value(cs.CtContextAccessToken).(string)

Expand All @@ -531,10 +559,10 @@ func (c *component) SetTrustIDGroups(ctx context.Context, realmName, userID stri

// set the trustID groups attributes
if currentUser.Attributes == nil {
var emtpyMap = make(kc.Attributes)
currentUser.Attributes = &emtpyMap
var emptyMap = make(kc.Attributes)
currentUser.Attributes = &emptyMap
}
(*currentUser.Attributes)["trustIDGroups"] = extGroupNames
(*currentUser.Attributes)[constants.AttrbTrustIDGroups] = extGroupNames

err = c.keycloakClient.UpdateUser(accessToken, realmName, userID, currentUser)
if err != nil {
Expand Down
59 changes: 59 additions & 0 deletions pkg/management/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
api "github.com/cloudtrust/keycloak-bridge/api/management"
"github.com/cloudtrust/keycloak-bridge/internal/constants"
"github.com/cloudtrust/keycloak-bridge/internal/dto"
"github.com/cloudtrust/keycloak-client"

"github.com/cloudtrust/keycloak-bridge/pkg/management/mock"
kc "github.com/cloudtrust/keycloak-client"
Expand Down Expand Up @@ -1404,6 +1405,64 @@ func TestGetGroupsOfUser(t *testing.T) {
}
}

func TestGetAvailableTrustIDGroups(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 = log.NewNopLogger()

var allowedTrustIDGroups = []string{"grp1", "grp2"}
var realmName = "master"

var component = NewComponent(mockKeycloakClient, mockEventDBModule, mockConfigurationDBModule, allowedTrustIDGroups, mockLogger)

var res, err = component.GetAvailableTrustIDGroups(context.TODO(), realmName)
assert.Nil(t, err)
assert.Len(t, res, len(allowedTrustIDGroups))
}

func TestGetTrustIDGroups(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 = log.NewNopLogger()

var allowedTrustIDGroups = []string{"grp1", "grp2"}
var groups = []string{"some", "/groups"}
var accessToken = "TOKEN=="
var realmName = "master"
var userID = "789-789-456"
var attrbs = keycloak.Attributes{constants.AttrbTrustIDGroups: groups}
var ctx = context.WithValue(context.TODO(), cs.CtContextAccessToken, accessToken)

var component = NewComponent(mockKeycloakClient, mockEventDBModule, mockConfigurationDBModule, allowedTrustIDGroups, mockLogger)

t.Run("Keycloak fails", func(t *testing.T) {
mockKeycloakClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kc.UserRepresentation{}, errors.New("kc error"))
var _, err = component.GetTrustIDGroups(ctx, realmName, userID)
assert.NotNil(t, err)
})
t.Run("User without attributes", func(t *testing.T) {
mockKeycloakClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kc.UserRepresentation{}, nil)
var res, err = component.GetTrustIDGroups(ctx, realmName, userID)
assert.Nil(t, err)
assert.Len(t, res, 0)
})
t.Run("User has attributes", func(t *testing.T) {
mockKeycloakClient.EXPECT().GetUser(accessToken, realmName, userID).Return(kc.UserRepresentation{Attributes: &attrbs}, nil)
var res, err = component.GetTrustIDGroups(ctx, realmName, userID)
assert.Nil(t, err)
assert.Equal(t, "some", res[0])
assert.Equal(t, "groups", res[1]) // Without heading slash
})
}

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

0 comments on commit 896fc30

Please sign in to comment.