Skip to content

Commit 03e1447

Browse files
feat: mapping admin based on OIDC groups
1 parent be38176 commit 03e1447

3 files changed

Lines changed: 48 additions & 1 deletion

File tree

api/login.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ type claimResult struct {
555555
username string
556556
name string
557557
email string
558+
admin bool
558559
}
559560

560561
func parseClaim(str string, claims map[string]any) (string, bool) {
@@ -629,6 +630,10 @@ func parseClaims(claims map[string]any, provider util.ClaimsProvider) (res claim
629630
res.name = getRandomProfileName()
630631
}
631632

633+
if provider.IsAdminMappingEnable() {
634+
res.admin = provider.IsAdminUserClaims(claims)
635+
}
636+
632637
return
633638
}
634639

@@ -793,6 +798,17 @@ func oidcRedirect(w http.ResponseWriter, r *http.Request) {
793798
return
794799
}
795800

801+
if provider.IsAdminMappingEnable() {
802+
user.Admin = claims.admin
803+
}
804+
805+
err = helpers.Store(r).UpdateUser(db.UserWithPwd{Pwd: "", User: user})
806+
if err != nil {
807+
log.Error(fmt.Errorf("Failed update OIDC user '%s': %v", user.Username, err))
808+
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
809+
return
810+
}
811+
796812
createSession(w, r, user, true)
797813

798814
config, ok := util.Config.OidcProviders[pid]

util/OdbcProvider.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,36 @@ type OidcProvider struct {
1515
UsernameClaim string `json:"username_claim" default:"preferred_username"`
1616
NameClaim string `json:"name_claim" default:"preferred_username"`
1717
EmailClaim string `json:"email_claim" default:"email"`
18+
GroupsClaim string `json:"groups_claim" default:"groups"`
19+
AdminGroup string `json:"admin_group" default:""` // Group from the groups in the claims that members will be map as admin on semaphore
1820
Order int `json:"order"`
1921
// ReturnViaState when true, passes the return path via the OAuth state parameter instead of the redirect URL path. This is useful for OAuth providers that have strict redirect URL validation.
20-
ReturnViaState bool `json:"return_via_state"`
22+
ReturnViaState bool `json:"return_via_state"`
2123
}
2224

2325
type ClaimsProvider interface {
2426
GetUsernameClaim() string
2527
GetEmailClaim() string
2628
GetNameClaim() string
29+
IsAdminMappingEnable() bool
30+
IsAdminUserClaims(claims map[string]any) bool
31+
}
32+
33+
func (p *OidcProvider) IsAdminMappingEnable() bool {
34+
return p.AdminGroup != ""
35+
}
36+
37+
func (p *OidcProvider) IsAdminUserClaims(claims map[string]any) bool {
38+
if rawList, ok := claims[p.GroupsClaim].([]any); ok {
39+
for _, g := range rawList {
40+
if group, ok := g.(string); ok {
41+
if p.AdminGroup == group {
42+
return true
43+
}
44+
}
45+
}
46+
}
47+
return false
2748
}
2849

2950
func (p *OidcProvider) GetUsernameClaim() string {

util/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ type LdapMappings struct {
6464
CN string `json:"cn" env:"SEMAPHORE_LDAP_MAPPING_CN" default:"cn"`
6565
}
6666

67+
func (p *LdapMappings) IsAdminMappingEnable() bool {
68+
// Always returns ‘not implemented’ with LDAP
69+
return false
70+
}
71+
72+
func (p *LdapMappings) IsAdminUserClaims(claims map[string]any) bool {
73+
// Always returns ‘not implemented’ with LDAP
74+
return false
75+
}
76+
6777
func (p *LdapMappings) GetUsernameClaim() string {
6878
return p.UID
6979
}

0 commit comments

Comments
 (0)