Skip to content

Commit

Permalink
Merge 4c829cd into e4595cb
Browse files Browse the repository at this point in the history
  • Loading branch information
lagess committed Jan 29, 2020
2 parents e4595cb + 4c829cd commit af0c725
Show file tree
Hide file tree
Showing 13 changed files with 343 additions and 48 deletions.
4 changes: 2 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions api/management/api.go
Expand Up @@ -26,6 +26,7 @@ type UserRepresentation struct {
BirthDate *string `json:"birthDate,omitempty"`
CreatedTimestamp *int64 `json:"createdTimestamp,omitempty"`
Groups *[]string `json:"groups,omitempty"`
TrustIDGroups *[]string `json:"trustIdGroups,omitempty"`
Roles *[]string `json:"roles,omitempty"`
Locale *string `json:"locale,omitempty"`
SmsSent *int `json:"smsSent,omitempty"`
Expand Down Expand Up @@ -194,6 +195,11 @@ func ConvertToAPIUser(userKc kc.UserRepresentation) UserRepresentation {
counter, _ := strconv.Atoi(smsSent)
userRep.SmsSent = &counter
}

if m["trustIDGroups"] != nil {
var trustIDGroups = m["trustIDGroups"]
userRep.TrustIDGroups = &trustIDGroups
}
}
return userRep
}
Expand Down
7 changes: 7 additions & 0 deletions api/management/api_test.go
Expand Up @@ -74,6 +74,12 @@ func TestConvertToAPIUser(t *testing.T) {
kcUser.Attributes = &m
m["smsSent"] = []string{"0"}
assert.NotNil(t, *ConvertToAPIUser(kcUser).SmsSent)

// trustID groups
assert.Nil(t, ConvertToAPIUser(kcUser).TrustIDGroups)
kcUser.Attributes = &m
m["trustIDGroups"] = []string{"en"}
assert.NotNil(t, *ConvertToAPIUser(kcUser).TrustIDGroups)
}

func TestConvertToAPIUsersPage(t *testing.T) {
Expand Down Expand Up @@ -131,6 +137,7 @@ func TestConvertToKCUser(t *testing.T) {
var locale = "it"
user.Locale = &locale
assert.Equal(t, locale, (*ConvertToKCUser(user).Attributes)["locale"][0])

}

func TestConvertToKCGroup(t *testing.T) {
Expand Down
17 changes: 16 additions & 1 deletion cmd/keycloakb/keycloak_bridge.go
Expand Up @@ -215,6 +215,9 @@ func main() {
}
}

// Security - allowed trustID groups
var trustIDGroups = c.GetStringSlice("trustid-groups")

// Keycloak client.
var keycloakClient *keycloak.Client
{
Expand Down Expand Up @@ -480,7 +483,7 @@ func main() {

var keycloakComponent management.Component
{
keycloakComponent = management.NewComponent(keycloakClient, eventsDBModule, configDBModule, managementLogger)
keycloakComponent = management.NewComponent(keycloakClient, eventsDBModule, configDBModule, trustIDGroups, managementLogger)
keycloakComponent = management.MakeAuthorizationManagementComponentMW(log.With(managementLogger, "mw", "endpoint"), authorizationManager)(keycloakComponent)
}

Expand All @@ -501,6 +504,7 @@ func main() {
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"]),

GetRoles: prepareEndpoint(management.MakeGetRolesEndpoint(keycloakComponent), "get_roles_endpoint", influxMetrics, managementLogger, tracer, rateLimit["management"]),
Expand Down Expand Up @@ -717,6 +721,7 @@ 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 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)
var addClientRoleToUserHandler = configureManagementHandler(keycloakb.ComponentName, ComponentID, idGenerator, keycloakClient, audienceRequired, tracer, logger)(managementEndpoints.AddClientRoleToUser)
Expand Down Expand Up @@ -771,6 +776,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("PUT").Handler(setTrustIDGroupsHandler)

// role mappings
managementSubroute.Path("/realms/{realm}/users/{userID}/role-mappings/clients/{clientID}").Methods("GET").Handler(getClientRoleForUserHandler)
Expand Down Expand Up @@ -937,6 +943,15 @@ func config(ctx context.Context, logger log.Logger) *viper.Viper {
// Security - Audience check
v.SetDefault("audience-required", "")
v.SetDefault("event-basic-auth-token", "")
v.SetDefault("trustid-groups",
[]string{
"l1_support_manager",
"l1_support_agent",
"product_administrator",
"registration_officer",
"papercard_administrator",
"technical",
"end_user"})

// CORS configuration
v.SetDefault("cors-allowed-origins", []string{})
Expand Down
5 changes: 5 additions & 0 deletions configs/authorization.json
Expand Up @@ -31,6 +31,11 @@
"*": {}
}
},
"MGMT_SetTrustIDGroups": {
"*": {
"*": {}
}
},
"MGMT_GetGroups": {
"master": {
"*": {}
Expand Down
11 changes: 11 additions & 0 deletions configs/keycloak_bridge.yml
Expand Up @@ -42,6 +42,17 @@ audience-required: "account"
## Password used to protect /internal/event endpoint
event-basic-auth-token: "superpasswordverylongandstrong"


## trustID groups allowed to be set
trustid-groups:
- "l1_support_manager"
- "l1_support_agent"
- "product_administrator"
- "registration_officer"
- "papercard_administrator"
- "technical"
- "end_user"

# Keycloak configs
keycloak-api-uri: http://localhost:8080
keycloak-oidc-uri: http://localhost:8080 http://127.0.0.1:8080
Expand Down
1 change: 1 addition & 0 deletions internal/messages/errormessages.go
Expand Up @@ -64,4 +64,5 @@ const (
Max = "max"
Timeshift = "timeshift"
IdentityProvider = "identityProvider"
TrustIDGroupName = "trustIDGroupName"
)
12 changes: 12 additions & 0 deletions pkg/management/authorization.go
Expand Up @@ -36,6 +36,7 @@ var (
MGMTGetUserAccountStatus = newAction("MGMT_GetUserAccountStatus", security.ScopeGroup)
MGMTGetRolesOfUser = newAction("MGMT_GetRolesOfUser", security.ScopeGroup)
MGMTGetGroupsOfUser = newAction("MGMT_GetGroupsOfUser", security.ScopeGroup)
MGMTSetTrustIDGroups = newAction("MGMT_SetTrustIDGroups", security.ScopeGroup)
MGMTGetClientRolesForUser = newAction("MGMT_GetClientRolesForUser", security.ScopeGroup)
MGMTAddClientRolesToUser = newAction("MGMT_AddClientRolesToUser", security.ScopeGroup)
MGMTResetPassword = newAction("MGMT_ResetPassword", security.ScopeGroup)
Expand Down Expand Up @@ -237,6 +238,17 @@ func (c *authorizationComponentMW) GetGroupsOfUser(ctx context.Context, realmNam
return c.next.GetGroupsOfUser(ctx, realmName, userID)
}

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

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

return c.next.SetTrustIDGroups(ctx, realmName, userID, groupNames)
}

func (c *authorizationComponentMW) GetClientRolesForUser(ctx context.Context, realmName, userID, clientID string) ([]api.RoleRepresentation, error) {
var action = MGMTGetClientRolesForUser.String()
var targetRealm = realmName
Expand Down
10 changes: 10 additions & 0 deletions pkg/management/authorization_test.go
Expand Up @@ -36,6 +36,7 @@ func TestDeny(t *testing.T) {
var groupID = "123-789-454"
var groupIDs = []string{groupID}
var groupName = "titi"
var grpNames = []string{"grp1", "grp2"}

var authzMatrix = map[string]map[string]map[string]struct{}{}

Expand Down Expand Up @@ -138,6 +139,9 @@ func TestDeny(t *testing.T) {
_, err = authorizationMW.GetGroupsOfUser(ctx, realmName, userID)
assert.Equal(t, security.ForbiddenError{}, err)

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

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

Expand Down Expand Up @@ -231,6 +235,7 @@ func TestAllowed(t *testing.T) {
var groupID = "123-789-454"
var groupIDs = []string{groupID}
var groupName = "titi"
var grpNames = []string{"grp1", "grp2"}

var authzMatrix = map[string]map[string]map[string]struct{}{}

Expand Down Expand Up @@ -295,6 +300,7 @@ func TestAllowed(t *testing.T) {
"MGMT_GetUserAccountStatus": {"*": {"*": {} }},
"MGMT_GetRolesOfUser": {"*": {"*": {} }},
"MGMT_GetGroupsOfUser": {"*": {"*": {} }},
"MGMT_SetTrustIDGroups": {"*": {"*": {} }},
"MGMT_GetClientRolesForUser": {"*": {"*": {} }},
"MGMT_AddClientRolesToUser": {"*": {"*": {} }},
"MGMT_ResetPassword": {"*": {"*": {} }},
Expand Down Expand Up @@ -439,6 +445,10 @@ func TestAllowed(t *testing.T) {
_, err = authorizationMW.GetGroups(ctx, realmName)
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)

mockManagementComponent.EXPECT().CreateGroup(ctx, realmName, group).Return("", nil).Times(1)
_, err = authorizationMW.CreateGroup(ctx, realmName, group)
assert.Nil(t, err)
Expand Down
64 changes: 55 additions & 9 deletions pkg/management/component.go
Expand Up @@ -89,6 +89,7 @@ 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)
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 @@ -119,20 +120,28 @@ type Component interface {

// Component is the management component.
type component struct {
keycloakClient KeycloakClient
eventDBModule database.EventsDBModule
configDBModule ConfigurationDBModule
logger keycloakb.Logger
keycloakClient KeycloakClient
eventDBModule database.EventsDBModule
configDBModule ConfigurationDBModule
authorizedTrustIDGroups map[string]bool
logger keycloakb.Logger
}

// NewComponent returns the management component.
func NewComponent(keycloakClient KeycloakClient, eventDBModule database.EventsDBModule,
configDBModule ConfigurationDBModule, logger keycloakb.Logger) Component {
configDBModule ConfigurationDBModule, authorizedTrustIDGroups []string, logger keycloakb.Logger) Component {

var authzedTrustIDGroups = make(map[string]bool)
for _, grp := range authorizedTrustIDGroups {
authzedTrustIDGroups[grp] = true
}

return &component{
keycloakClient: keycloakClient,
eventDBModule: eventDBModule,
configDBModule: configDBModule,
logger: logger,
keycloakClient: keycloakClient,
eventDBModule: eventDBModule,
configDBModule: configDBModule,
authorizedTrustIDGroups: authzedTrustIDGroups,
logger: logger,
}
}

Expand Down Expand Up @@ -498,6 +507,43 @@ func (c *component) GetGroupsOfUser(ctx context.Context, realmName, userID strin
return groupsRep, nil
}

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

// validate the input - trustID groups must be valid
var extGroupNames []string
for _, groupName := range groupNames {
if _, ok := c.authorizedTrustIDGroups[groupName]; ok {
extGroupNames = append(extGroupNames, "/"+groupName)
} else {
// unauthorized call (unknown trustID group) --> error
c.logger.Warn(ctx, "msg", groupName+" group is not allowed to be set as a trustID group")
return errorhandler.CreateBadRequestError(msg.MsgErrInvalidParam + "." + msg.TrustIDGroupName)
}
}

// get the "old" user representation
currentUser, err := c.keycloakClient.GetUser(accessToken, realmName, userID)
if err != nil {
c.logger.Warn(ctx, "err", err.Error())
return err
}

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

err = c.keycloakClient.UpdateUser(accessToken, realmName, userID, currentUser)
if err != nil {
c.logger.Warn(ctx, "err", err.Error())
return err
}
return nil
}

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

Expand Down

0 comments on commit af0c725

Please sign in to comment.