fix: add authURLParams to urls for external idps (#5404)

add authURL parameters to urls for external IDPs, depended on the contents of the authRequest

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz 2023-03-14 16:42:29 +01:00 committed by GitHub
parent 1f302fce96
commit f99cf50f69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 7 deletions

View File

@ -136,6 +136,7 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
return
}
var provider idp.Provider
switch identityProvider.Type {
case domain.IDPTypeOAuth:
provider, err = l.oauthProvider(r.Context(), identityProvider)
@ -165,7 +166,8 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
l.renderLogin(w, r, authReq, err)
return
}
session, err := provider.BeginAuth(r.Context(), authReq.ID, authReq.AgentID)
params := l.sessionParamsFromAuthRequest(r.Context(), authReq, identityProvider.ID)
session, err := provider.BeginAuth(r.Context(), authReq.ID, params...)
if err != nil {
l.renderLogin(w, r, authReq, err)
return
@ -801,7 +803,7 @@ func mapExternalUserToLoginUser(externalUser *domain.ExternalUser, mustBeDomain
externalIDP := &domain.UserIDPLink{
IDPConfigID: externalUser.IDPConfigID,
ExternalUserID: externalUser.ExternalUserID,
DisplayName: externalUser.DisplayName,
DisplayName: externalUser.PreferredUsername,
}
return human, externalIDP, externalUser.Metadatas
}
@ -824,3 +826,53 @@ func mapExternalNotFoundOptionFormDataToLoginUser(formData *externalNotFoundOpti
PreferredLanguage: language.Make(formData.Language),
}
}
func (l *Login) sessionParamsFromAuthRequest(ctx context.Context, authReq *domain.AuthRequest, identityProviderID string) []any {
params := []any{authReq.AgentID}
if authReq.UserID != "" && identityProviderID != "" {
links, err := l.getUserLinks(ctx, authReq.UserID, identityProviderID)
if err != nil {
logging.WithFields("authReqID", authReq.ID, "userID", authReq.UserID, "providerID", identityProviderID).WithError(err).Warn("failed to get user links for")
return params
}
if len(links.Links) == 1 {
return append(params, keyAndValueToAuthURLOpt("login_hint", links.Links[0].ProvidedUsername))
}
}
if authReq.UserName != "" {
return append(params, keyAndValueToAuthURLOpt("login_hint", authReq.UserName))
}
if authReq.LoginName != "" {
return append(params, keyAndValueToAuthURLOpt("login_hint", authReq.LoginName))
}
if authReq.LoginHint != "" {
return append(params, keyAndValueToAuthURLOpt("login_hint", authReq.LoginHint))
}
return params
}
func keyAndValueToAuthURLOpt(key, value string) rp.AuthURLOpt {
return func() []oauth2.AuthCodeOption {
return []oauth2.AuthCodeOption{oauth2.SetAuthURLParam(key, value)}
}
}
func (l *Login) getUserLinks(ctx context.Context, userID, idpID string) (*query.IDPUserLinks, error) {
userIDQuery, err := query.NewIDPUserLinksUserIDSearchQuery(userID)
if err != nil {
return nil, err
}
idpIDQuery, err := query.NewIDPUserLinkIDPIDSearchQuery(idpID)
if err != nil {
return nil, err
}
return l.query.IDPUserLinks(ctx,
&query.IDPUserLinksSearchQuery{
Queries: []query.SearchQuery{
userIDQuery,
idpIDQuery,
},
}, false,
)
}

View File

@ -92,7 +92,7 @@ func (p *Provider) Name() string {
// It will create a [Session] with an AuthURL, pointing to the jwtEndpoint
// with the authRequest and encrypted userAgent ids.
func (p *Provider) BeginAuth(ctx context.Context, state string, params ...any) (idp.Session, error) {
if len(params) != 1 {
if len(params) < 1 {
return nil, ErrMissingUserAgentID
}
userAgentID, ok := params[0].(string)

View File

@ -87,8 +87,14 @@ func (p *Provider) Name() string {
// BeginAuth implements the [idp.Provider] interface.
// It will create a [Session] with an OAuth2.0 authorization request as AuthURL.
func (p *Provider) BeginAuth(ctx context.Context, state string, _ ...any) (idp.Session, error) {
url := rp.AuthURL(state, p.RelyingParty, rp.WithPrompt(oidc.PromptSelectAccount))
func (p *Provider) BeginAuth(ctx context.Context, state string, params ...any) (idp.Session, error) {
opts := []rp.AuthURLOpt{rp.WithPrompt(oidc.PromptSelectAccount)}
for _, param := range params {
if option, ok := param.(rp.AuthURLOpt); ok {
opts = append(opts, option)
}
}
url := rp.AuthURL(state, p.RelyingParty, opts...)
return &Session{AuthURL: url, Provider: p}, nil
}

View File

@ -112,8 +112,14 @@ func (p *Provider) Name() string {
// BeginAuth implements the [idp.Provider] interface.
// It will create a [Session] with an OIDC authorization request as AuthURL.
func (p *Provider) BeginAuth(ctx context.Context, state string, _ ...any) (idp.Session, error) {
url := rp.AuthURL(state, p.RelyingParty, p.authOptions...)
func (p *Provider) BeginAuth(ctx context.Context, state string, params ...any) (idp.Session, error) {
opts := p.authOptions
for _, param := range params {
if option, ok := param.(rp.AuthURLOpt); ok {
opts = append(opts, option)
}
}
url := rp.AuthURL(state, p.RelyingParty, opts...)
return &Session{AuthURL: url, Provider: p}, nil
}