From 03cf5a5c083765a7b08146adefe243b887037c1f Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Mon, 23 May 2022 17:55:38 +0200 Subject: [PATCH] Replace ThreePID lookups with the new SSO lookups. --- clientapi/auth/sso/oidc_base.go | 60 +++++++++++++++++++-------------- clientapi/auth/sso/sso.go | 9 +++-- clientapi/routing/sso.go | 23 +++++++------ 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/clientapi/auth/sso/oidc_base.go b/clientapi/auth/sso/oidc_base.go index 20cd7b2cb..4275e5733 100644 --- a/clientapi/auth/sso/oidc_base.go +++ b/clientapi/auth/sso/oidc_base.go @@ -26,7 +26,7 @@ import ( "text/template" "github.com/matrix-org/dendrite/clientapi/jsonerror" - "github.com/matrix-org/dendrite/clientapi/userutil" + uapi "github.com/matrix-org/dendrite/userapi/api" "github.com/tidwall/gjson" ) @@ -161,7 +161,7 @@ func (p *baseOIDCIdentityProvider) getOIDCAccessToken(ctx context.Context, req * return resp.AccessToken, nil } -func (p *baseOIDCIdentityProvider) getUserInfo(ctx context.Context, req *IdentityProviderRequest, oidcAccessToken string) (*userutil.ThirdPartyIdentifier, string, error) { +func (p *baseOIDCIdentityProvider) getUserInfo(ctx context.Context, req *IdentityProviderRequest, oidcAccessToken string) (ssoUser *UserIdentifier, suggestedUserID string, _ error) { u, err := p.UserInfoURL.Execute(map[string]interface{}{ "Config": req.System, }, nil) @@ -187,34 +187,44 @@ func (p *baseOIDCIdentityProvider) getUserInfo(ctx context.Context, req *Identit return nil, "", err } - var email string - var suggestedUserID string - switch ctype { - case "application/json": - body, err := ioutil.ReadAll(hresp.Body) - if err != nil { - return nil, "", err - } - - emailRes := gjson.GetBytes(body, p.UserInfoEmailPath) - if !emailRes.Exists() { - return nil, "", fmt.Errorf("no email in user info response body") - } - email = emailRes.String() - - // This is optional. - userIDRes := gjson.GetBytes(body, p.UserInfoSuggestedUserIDPath) - suggestedUserID = userIDRes.String() - - default: + if ctype != "application/json" { return nil, "", fmt.Errorf("got unknown content type %q for user info", ctype) } - if email == "" { - return nil, "", fmt.Errorf("no email address in user info") + body, err := ioutil.ReadAll(hresp.Body) + if err != nil { + return nil, "", err } - return &userutil.ThirdPartyIdentifier{Medium: "email", Address: email}, suggestedUserID, nil + issRes := gjson.GetBytes(body, "iss") + if !issRes.Exists() { + return nil, "", fmt.Errorf("no iss in user info response body") + } + iss := issRes.String() + + subRes := gjson.GetBytes(body, "sub") + if !subRes.Exists() { + return nil, "", fmt.Errorf("no sub in user info response body") + } + sub := subRes.String() + + if iss == "" { + return nil, "", fmt.Errorf("no iss in user info") + } + + if sub == "" { + return nil, "", fmt.Errorf("no sub in user info") + } + + // This is optional. + userIDRes := gjson.GetBytes(body, p.UserInfoSuggestedUserIDPath) + suggestedUserID = userIDRes.String() + + return &UserIdentifier{ + Namespace: uapi.OIDCNamespace, + Issuer: iss, + Subject: sub, + }, suggestedUserID, nil } type urlTemplate struct { diff --git a/clientapi/auth/sso/sso.go b/clientapi/auth/sso/sso.go index 653863d8f..37e3842a8 100644 --- a/clientapi/auth/sso/sso.go +++ b/clientapi/auth/sso/sso.go @@ -18,8 +18,8 @@ import ( "context" "net/url" - "github.com/matrix-org/dendrite/clientapi/userutil" "github.com/matrix-org/dendrite/setup/config" + uapi "github.com/matrix-org/dendrite/userapi/api" ) type IdentityProvider interface { @@ -37,7 +37,7 @@ type IdentityProviderRequest struct { type CallbackResult struct { RedirectURL string - Identifier *userutil.ThirdPartyIdentifier + Identifier *UserIdentifier SuggestedUserID string } @@ -55,3 +55,8 @@ func GetIdentityProvider(t IdentityProviderType) IdentityProvider { return nil } } + +type UserIdentifier struct { + Namespace uapi.SSOIssuerNamespace + Issuer, Subject string +} diff --git a/clientapi/routing/sso.go b/clientapi/routing/sso.go index e9e4e5518..17c95a8ca 100644 --- a/clientapi/routing/sso.go +++ b/clientapi/routing/sso.go @@ -165,9 +165,9 @@ func SSOCallback( return util.RedirectResponse(result.RedirectURL) } - id, err := verifyThirdPartyUserIdentifier(ctx, userAPI, result.Identifier, cfg.Matrix.ServerName) + id, err := verifySSOUserIdentifier(ctx, userAPI, result.Identifier, cfg.Matrix.ServerName) if err != nil { - util.GetLogger(ctx).WithError(err).WithField("identifier", result.Identifier.String()).Error("failed to find user") + util.GetLogger(ctx).WithError(err).WithField("identifier", result.Identifier).Error("failed to find user") return util.JSONResponse{ Code: http.StatusUnauthorized, JSON: jsonerror.Forbidden("ID not associated with a local account"), @@ -176,7 +176,7 @@ func SSOCallback( if id == nil { // The user doesn't exist. // TODO: let the user select a localpart and register an account. - util.GetLogger(ctx).WithError(err).WithField("identifier", result.Identifier.String()).Error("failed to find user") + util.GetLogger(ctx).WithError(err).WithField("identifier", result.Identifier).Error("failed to find user") return util.JSONResponse{ Code: http.StatusNotImplemented, JSON: jsonerror.Forbidden("SSO registration not implemented"), @@ -204,7 +204,7 @@ func SSOCallback( type userAPIForSSO interface { uapi.LoginTokenInternalAPI - QueryLocalpartForThreePID(ctx context.Context, req *uapi.QueryLocalpartForThreePIDRequest, res *uapi.QueryLocalpartForThreePIDResponse) error + QueryLocalpartForSSO(ctx context.Context, req *uapi.QueryLocalpartForSSORequest, res *uapi.QueryLocalpartForSSOResponse) error } // getProvider looks up the given provider in the @@ -254,16 +254,17 @@ func parseNonce(s string) (redirectURL *url.URL, _ error) { return u, nil } -// verifyThirdPartyUserIdentifier resolves a ThirdPartyIdentifier to a +// verifySSOUserIdentifier resolves an sso.UserIdentifier to a // UserIdentifier using the User API. Returns nil if there is no // associated user. -func verifyThirdPartyUserIdentifier(ctx context.Context, userAPI userAPIForSSO, id *userutil.ThirdPartyIdentifier, serverName gomatrixserverlib.ServerName) (*userutil.UserIdentifier, error) { - req := &uapi.QueryLocalpartForThreePIDRequest{ - ThreePID: id.Address, - Medium: string(id.Medium), +func verifySSOUserIdentifier(ctx context.Context, userAPI userAPIForSSO, id *sso.UserIdentifier, serverName gomatrixserverlib.ServerName) (*userutil.UserIdentifier, error) { + req := &uapi.QueryLocalpartForSSORequest{ + Namespace: id.Namespace, + Issuer: id.Issuer, + Subject: id.Subject, } - var res uapi.QueryLocalpartForThreePIDResponse - if err := userAPI.QueryLocalpartForThreePID(ctx, req, &res); err != nil { + var res uapi.QueryLocalpartForSSOResponse + if err := userAPI.QueryLocalpartForSSO(ctx, req, &res); err != nil { return nil, err } if res.Localpart == "" {