Skip to content

Commit

Permalink
Implement oidc group -> local user mapping
Browse files Browse the repository at this point in the history
Refactor names towards general oidc mapping
  • Loading branch information
Antoon Prins committed Nov 11, 2021
1 parent 6829215 commit 55367df
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 30 deletions.
12 changes: 12 additions & 0 deletions examples/oidc-mapping/users-oidcmapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"oidc_issuer": "http://iam-login-service:8080/",
"oidc_group": "Analysis",
"opaque_id": "4c510ada-c86b-4815-8820-42cdf82c3d51"
},
{
"oidc_issuer": "http://iam-login-service:8080/",
"oidc_group": "Sciencemesh",
"opaque_id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"
}
]
4 changes: 2 additions & 2 deletions examples/oidc-mapping/users-oidcmapping.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ users = "users.json"
[grpc.services.authprovider.auth_managers.oidcmapping]
issuer = "http://iam-login-service:8080/"
userprovidersvc = "0.0.0.0:13000"
# The ESCAPE IAM users mapping file path
users = "/etc/revad/iam-escape-users.json"
# The OIDC users mapping file path
usersmapping = "/go/src/github/cs3org/reva/examples/oidc-mapping/users-oidcmapping.json"

[grpc.services.userprovider]
driver = "json"
Expand Down
73 changes: 45 additions & 28 deletions pkg/auth/manager/oidcmapping/oidcmapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import (
oidc "github.com/coreos/go-oidc"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/auth"
"github.com/cs3org/reva/pkg/auth/manager/registry"
"github.com/cs3org/reva/pkg/auth/scope"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/rhttp"
"github.com/juliangruber/go-intersect"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"golang.org/x/oauth2"
Expand All @@ -44,9 +46,9 @@ func init() {
}

type mgr struct {
provider *oidc.Provider // cached on first request
c *config
iamUsers map[string]*iamUser
provider *oidc.Provider // cached on first request
c *config
oidcUsersMapping map[string]*oidcUserMapping
}

type config struct {
Expand All @@ -56,12 +58,13 @@ type config struct {
UIDClaim string `mapstructure:"uid_claim" docs:";The claim containing the UID of the user."`
GIDClaim string `mapstructure:"gid_claim" docs:";The claim containing the GID of the user."`
UserProviderSvc string `mapstructure:"userprovidersvc" docs:";The endpoint at which the GRPC userprovider is exposed."`
Users string `mapstructure:"users" docs:"; The IAM users mapping file path"`
UsersMapping string `mapstructure:"usersmapping" docs:"; The OIDC users mapping file path"`
}

type iamUser struct {
OpaqueID string `mapstructure:"opaque_id" json:"opaque_id"`
Sub string `mapstructure:"sub" json:"sub"`
type oidcUserMapping struct {
OIDCIssuer string `mapstructure:"oidc_issuer" json:"oidc_issuer"`
OIDCGroup string `mapstructure:"oidc_group" json:"oidc_group"`
OpaqueID string `mapstructure:"opaque_id" json:"opaque_id"`
}

func (c *config) init() {
Expand Down Expand Up @@ -97,21 +100,21 @@ func (am *mgr) Configure(m map[string]interface{}) error {
c.init()
am.c = c

am.iamUsers = map[string]*iamUser{}
f, err := ioutil.ReadFile(c.Users)
am.oidcUsersMapping = map[string]*oidcUserMapping{}
f, err := ioutil.ReadFile(c.UsersMapping)
if err != nil {
return fmt.Errorf("oidcmapping: error reading escape iam users file: +%v", err)
return fmt.Errorf("oidcmapping: error reading oidc users mapping file: +%v", err)
}

iamUsers := []*iamUser{}
oidcUsers := []*oidcUserMapping{}

err = json.Unmarshal(f, &iamUsers)
err = json.Unmarshal(f, &oidcUsers)
if err != nil {
return fmt.Errorf("oidcmapping: error unmarshalling escape iam users file: +%v", err)
return fmt.Errorf("oidcmapping: error unmarshalling oidc users mapping file: +%v", err)
}

for _, u := range iamUsers {
am.iamUsers[u.Sub] = u
for _, u := range oidcUsers {
am.oidcUsersMapping[u.OIDCGroup] = u
}

return nil
Expand Down Expand Up @@ -164,12 +167,27 @@ func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string)
return nil, nil, fmt.Errorf("oidcmapping: no \"groups\" attribute found in userinfo")
}

// find local user opaqueID
// discover the user opaqueID
var opaqueID string
if iamUser, ok := am.iamUsers[claims[am.c.IDClaim].(string)]; ok {
opaqueID = iamUser.OpaqueID

mappings := make([]string, 0, len(am.oidcUsersMapping))
for _, v := range am.oidcUsersMapping {
if v.OIDCIssuer == claims["issuer"] {
mappings = append(mappings, v.OIDCGroup)
}
}
intersection := intersect.Simple(claims["groups"], mappings)
if len(intersection.([]interface{})) > 1 {
// multiple mappings is not implemented, we don't know which one to choose
return nil, nil, errors.New("oidcmapping: mapping failed, more than one mapping found")
}
if len(intersection.([]interface{})) == 1 {
for _, m := range intersection.([]interface{}) {
opaqueID = am.oidcUsersMapping[m.(string)].OpaqueID
}
}
if opaqueID == "" {
// no mappings found
return nil, nil, errors.Wrap(err, "oidcmapping: unable to retrieve local user from claims")
}

Expand Down Expand Up @@ -201,21 +219,20 @@ func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string)
userID.Idp = getUserResp.GetUser().GetId().Idp
userID.Type = getUserResp.GetUser().GetId().Type

groups := make([]string, 0, len(claims["groups"].([]interface{})))
for _, v := range claims["groups"].([]interface{}) {
switch g := v.(type) {
case string:
groups = append(groups, v.(string))
default:
// TODO should we fail here?
log.Debug().Msgf("oidcmapping: retrieved group from token, expected type string, found: %T", g)
}
getGroupsResp, err := gwc.GetUserGroups(ctx, &user.GetUserGroupsRequest{
UserId: userID,
})
if err != nil {
return nil, nil, errors.Wrap(err, "oidcmapping: error getting user groups")
}
if getGroupsResp.Status.Code != rpc.Code_CODE_OK {
return nil, nil, errors.Wrap(err, "oidcmapping: grpc getting user groups failed")
}

u := &user.User{
Id: userID,
Username: getUserResp.GetUser().GetUsername(),
Groups: groups,
Groups: getUserResp.GetUser().GetGroups(),
Mail: claims["email"].(string),
MailVerified: claims["email_verified"].(bool),
DisplayName: claims["name"].(string),
Expand Down

0 comments on commit 55367df

Please sign in to comment.