Skip to content

Commit 4d49cb4

Browse files
committed
feat(oidc): more detailed error messages and error validation
1 parent 2267c48 commit 4d49cb4

File tree

2 files changed

+39
-33
lines changed

2 files changed

+39
-33
lines changed

api/login.go

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -614,12 +614,13 @@ func oidcRedirect(w http.ResponseWriter, r *http.Request) {
614614
loginURL, _ := url.JoinPath(util.Config.WebHost, "auth/login")
615615

616616
if err != nil {
617-
log.Error(err.Error())
617+
log.Errorf("Failed to retrieve OAuth state cookie: %v", err)
618618
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
619619
return
620620
}
621621

622622
if r.FormValue("state") != oauthState.Value {
623+
log.Warn("OAuth state mismatch")
623624
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
624625
return
625626
}
@@ -628,54 +629,58 @@ func oidcRedirect(w http.ResponseWriter, r *http.Request) {
628629

629630
_oidc, oauth, err := getOidcProvider(pid, ctx, r.URL.Path)
630631
if err != nil {
631-
log.Error(err.Error())
632+
log.Errorf("Failed to get OIDC provider: %v", err)
632633
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
633634
return
634635
}
635636

636637
provider, ok := util.Config.OidcProviders[pid]
637638
if !ok {
638-
log.Error(fmt.Errorf("no such provider: %s", pid))
639+
log.Errorf("No such OIDC provider: %s", pid)
639640
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
640641
return
641642
}
642643

643644
verifier := _oidc.Verifier(&oidc.Config{ClientID: oauth.ClientID})
644645

645646
code := r.URL.Query().Get("code")
647+
if code == "" {
648+
log.Warn("Missing authorization code in request")
649+
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
650+
return
651+
}
646652

647653
oauth2Token, err := oauth.Exchange(ctx, code)
648654
if err != nil {
649-
log.Error(err.Error())
655+
log.Errorf("Failed to exchange authorization code: %v", err)
650656
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
651657
return
652658
}
653659

654660
var claims claimResult
655-
656-
// Extract the ID Token from OAuth2 token.
657661
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
658662

659663
if ok && rawIDToken != "" {
660-
var idToken *oidc.IDToken
661-
// Parse and verify ID Token payload.
662-
idToken, err = verifier.Verify(ctx, rawIDToken)
663-
664-
if err == nil {
665-
claims, err = claimOidcToken(idToken, provider)
664+
idToken, err := verifier.Verify(ctx, rawIDToken)
665+
if err != nil {
666+
log.Errorf("Failed to verify ID token: %v", err)
667+
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
668+
return
666669
}
670+
claims, err = claimOidcToken(idToken, provider)
667671
} else {
668-
var userInfo *oidc.UserInfo
669-
userInfo, err = _oidc.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
670-
671-
if err == nil {
672+
userInfo, err := _oidc.UserInfo(ctx, oauth2.StaticTokenSource(oauth2Token))
673+
if err != nil {
674+
log.Errorf("Failed to retrieve user info: %v", err)
675+
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
676+
return
677+
}
672678

673-
if userInfo.Email == "" {
674-
claims, err = claimOidcUserInfo(userInfo, provider)
675-
} else {
676-
claims.email = userInfo.Email
677-
claims.name = userInfo.Profile
678-
}
679+
if userInfo.Email == "" {
680+
claims, err = claimOidcUserInfo(userInfo, provider)
681+
} else {
682+
claims.email = userInfo.Email
683+
claims.name = userInfo.Profile
679684
}
680685

681686
claims.username = getRandomUsername()
@@ -685,40 +690,39 @@ func oidcRedirect(w http.ResponseWriter, r *http.Request) {
685690
}
686691

687692
if err != nil {
688-
log.Error(err.Error())
693+
log.Errorf("Failed to parse claims: %v", err)
689694
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
690695
return
691696
}
692697

693-
user, err := helpers.Store(r).GetUserByLoginOrEmail("", claims.email) // ignore username because it creates a lot of problems
694-
if err != nil {
698+
user, err := helpers.Store(r).GetUserByLoginOrEmail("", claims.email)
699+
if errors.Is(err, db.ErrNotFound) {
695700
user = db.User{
696701
Username: claims.username,
697702
Name: claims.name,
698703
Email: claims.email,
699704
External: true,
700705
}
701706
user, err = helpers.Store(r).CreateUserWithoutPassword(user)
702-
if err != nil {
703-
log.Error(err.Error())
704-
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
705-
return
706-
}
707+
}
708+
if err != nil {
709+
log.Errorf("Failed to create or retrieve user: %v", err)
710+
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
711+
return
707712
}
708713

709714
if !user.External {
710-
log.Error(fmt.Errorf("OIDC user '%s' conflicts with local user", user.Username))
715+
log.Errorf("OIDC user '%s' conflicts with local user", user.Username)
711716
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
712717
return
713718
}
714719

715720
createSession(w, r, user)
716721

717722
redirectPath := mux.Vars(r)["redirect_path"]
718-
719723
redirectPath, err = url.JoinPath(util.Config.WebHost, redirectPath)
720724
if err != nil {
721-
log.Error(err)
725+
log.Errorf("Failed to construct redirect path: %v", err)
722726
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
723727
return
724728
}

util/OdbcProvider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ type OidcProvider struct {
1616
NameClaim string `json:"name_claim" default:"preferred_username"`
1717
EmailClaim string `json:"email_claim" default:"email"`
1818
Order int `json:"order"`
19+
20+
DisableUserCreation bool `json:"disable_user_creation"`
1921
}
2022

2123
type ClaimsProvider interface {

0 commit comments

Comments
 (0)