Browse Source

Add more logging and better error messages for openid authentication + clarify docs

pull/865/head
kolaente 1 month ago
parent
commit
b76ad8efe2
Signed by: konrad GPG Key ID: F40E70337AB24C9B
  1. 6
      config.yml.sample
  2. 6
      docs/content/doc/setup/config.md
  3. 25
      pkg/modules/auth/openid/openid.go
  4. 26
      pkg/user/error.go

6
config.yml.sample

@ -262,10 +262,12 @@ auth:
enabled: true
# OpenID configuration will allow users to authenticate through a third-party OpenID Connect compatible provider.<br/>
# The provider needs to support the `openid`, `profile` and `email` scopes.<br/>
# **Note:** The frontend expects to be redirected after authentication by the third party
# **Note:** Some openid providers (like gitlab) only make the email of the user available through openid claims if they have set it to be publicly visible.
# If the email is not public in those cases, authenticating will fail.
# **Note 2:** The frontend expects to be redirected after authentication by the third party
# to <frontend-url>/auth/openid/<auth key>. Please make sure to configure the redirect url with your third party
# auth service accordingy if you're using the default vikunja frontend.
# Take a look at the [default config file](https://kolaente.dev/vikunja/api/src/branch/master/config.yml.sample) for more information about how to configure openid authentication.
# Take a look at the [default config file](https://kolaente.dev/vikunja/api/src/branch/main/config.yml.sample) for more information about how to configure openid authentication.
openid:
# Enable or disable OpenID Connect authentication
enabled: false

6
docs/content/doc/setup/config.md

@ -615,10 +615,12 @@ Default: `<empty>`
OpenID configuration will allow users to authenticate through a third-party OpenID Connect compatible provider.<br/>
The provider needs to support the `openid`, `profile` and `email` scopes.<br/>
**Note:** The frontend expects to be redirected after authentication by the third party
**Note:** Some openid providers (like gitlab) only make the email of the user available through openid claims if they have set it to be publicly visible.
If the email is not public in those cases, authenticating will fail.
**Note 2:** The frontend expects to be redirected after authentication by the third party
to <frontend-url>/auth/openid/<auth key>. Please make sure to configure the redirect url with your third party
auth service accordingy if you're using the default vikunja frontend.
Take a look at the [default config file](https://kolaente.dev/vikunja/api/src/branch/master/config.yml.sample) for more information about how to configure openid authentication.
Take a look at the [default config file](https://kolaente.dev/vikunja/api/src/branch/main/config.yml.sample) for more information about how to configure openid authentication.
Default: `<empty>`

25
pkg/modules/auth/openid/openid.go

@ -23,6 +23,8 @@ import (
"net/http"
"time"
"code.vikunja.io/web/handler"
"code.vikunja.io/api/pkg/db"
"xorm.io/xorm"
@ -86,7 +88,7 @@ func HandleCallback(c echo.Context) error {
provider, err := GetProvider(providerKey)
if err != nil {
log.Error(err)
return err
return handler.HandleHTTPError(err, c)
}
if provider == nil {
return c.JSON(http.StatusBadRequest, models.Message{Message: "Provider does not exist"})
@ -100,7 +102,8 @@ func HandleCallback(c echo.Context) error {
details := make(map[string]interface{})
if err := json.Unmarshal(rerr.Body, &details); err != nil {
return err
log.Errorf("Error unmarshaling token for provider %s: %v", provider.Name, err)
return handler.HandleHTTPError(err, c)
}
return c.JSON(http.StatusBadRequest, map[string]interface{}{
@ -109,7 +112,7 @@ func HandleCallback(c echo.Context) error {
})
}
return err
return handler.HandleHTTPError(err, c)
}
// Extract the ID Token from OAuth2 token.
@ -123,14 +126,21 @@ func HandleCallback(c echo.Context) error {
// Parse and verify ID Token payload.
idToken, err := verifier.Verify(context.Background(), rawIDToken)
if err != nil {
return err
log.Errorf("Error verifying token for provider %s: %v", provider.Name, err)
return handler.HandleHTTPError(err, c)
}
// Extract custom claims
cl := &claims{}
err = idToken.Claims(cl)
if err != nil {
return err
log.Errorf("Error getting token claims for provider %s: %v", provider.Name, err)
return handler.HandleHTTPError(err, c)
}
if cl.Email == "" {
log.Errorf("Claim does not contain an email address for provider %s", provider.Name)
return handler.HandleHTTPError(&user.ErrNoOpenIDEmailProvided{}, c)
}
s := db.NewSession()
@ -140,12 +150,13 @@ func HandleCallback(c echo.Context) error {
u, err := getOrCreateUser(s, cl, idToken.Issuer, idToken.Subject)
if err != nil {
_ = s.Rollback()
return err
log.Errorf("Error creating new user for provider %s: %v", provider.Name, err)
return handler.HandleHTTPError(err, c)
}
err = s.Commit()
if err != nil {
return err
return handler.HandleHTTPError(err, c)
}
// Create token

26
pkg/user/error.go

@ -399,3 +399,29 @@ func (err ErrInvalidAvatarProvider) HTTPError() web.HTTPError {
Message: "Invalid avatar provider setting. See docs for valid types.",
}
}
// ErrNoOpenIDEmailProvided represents a "NoEmailProvided" kind of error.
type ErrNoOpenIDEmailProvided struct {
}
// IsErrNoEmailProvided checks if an error is a ErrNoOpenIDEmailProvided.
func IsErrNoEmailProvided(err error) bool {
_, ok := err.(*ErrNoOpenIDEmailProvided)
return ok
}
func (err *ErrNoOpenIDEmailProvided) Error() string {
return "No email provided"
}
// ErrCodeNoOpenIDEmailProvided holds the unique world-error code of this error
const ErrCodeNoOpenIDEmailProvided = 1019
// HTTPError holds the http error description
func (err *ErrNoOpenIDEmailProvided) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeNoOpenIDEmailProvided,
Message: "No email address available. Please make sure the openid provider publicly provides an email address for your account.",
}
}
Loading…
Cancel
Save