-
-
Notifications
You must be signed in to change notification settings - Fork 931
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: partition files and change creds structure
This patch changes the data model of the OpenID Connect strategy. Instead of using an array of providers as the base config item (e.g. `{"type":"oidc","config":[{"provider":"google","subject":"..."}]}`) the credentials config is now an object with a `providers` key: `{"type":"oidc","config":{"providers":[{"provider":"google","subject":"..."}]}}`. This change allows introduction of future changes to the schema without breaking compatibility. BREAKING CHANGE: If you upgrade and have existing Social Sign In connections, it will no longer be possible to use them to sign in. Because the oidc strategy was undocumented and not officially released we do not provide an upgrade guide. If you run into this issue on a production system you may need to use SQL to change the config of those identities. If this is a real issue for you that you're unable to solve, please create an issue on GitHub.
- Loading branch information
Showing
5 changed files
with
365 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package oidc | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"net/http" | ||
|
||
"github.com/pkg/errors" | ||
|
||
"github.com/ory/herodot" | ||
|
||
"github.com/ory/kratos/identity" | ||
"github.com/ory/kratos/selfservice/flow/login" | ||
"github.com/ory/kratos/x" | ||
) | ||
|
||
var _ login.Strategy = new(Strategy) | ||
|
||
func (s *Strategy) RegisterLoginRoutes(r *x.RouterPublic) { | ||
s.setRoutes(r) | ||
} | ||
|
||
func (s *Strategy) PopulateLoginMethod(r *http.Request, sr *login.Request) error { | ||
config, err := s.populateMethod(r, sr.ID) | ||
if err != nil { | ||
return err | ||
} | ||
sr.Methods[s.ID()] = &login.RequestMethod{Method: s.ID(), | ||
Config: &login.RequestMethodConfig{RequestMethodConfigurator: config}} | ||
return nil | ||
} | ||
|
||
func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, a *login.Request, claims *Claims, provider Provider) { | ||
i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), identity.CredentialsTypeOIDC, uid(provider.Config().ID, claims.Subject)) | ||
if err != nil { | ||
if errors.Is(err, herodot.ErrNotFound) { | ||
// If no account was found we're "manually" creating a new registration request and redirecting the browser | ||
// to that endpoint. | ||
|
||
// That will execute the "pre registration" hook which allows to e.g. disallow this request. The registration | ||
// ui however will NOT be shown, instead the user is directly redirected to the auth path. That should then | ||
// do a silent re-request. While this might be a bit excessive from a network perspective it should usually | ||
// happen without any downsides to user experience as the request has already been authorized and should | ||
// not need additional consent/login. | ||
|
||
// This is kinda hacky but the only way to ensure seamless login/registration flows when using OIDC. | ||
|
||
s.d.Logger().WithField("provider", provider.Config().ID).WithField("subject", claims.Subject).Debug("Received successful OpenID Connect callback but user is not registered. Re-initializing registration flow now.") | ||
aa, err := s.d.RegistrationHandler().NewRegistrationRequest(w, r) | ||
if err != nil { | ||
s.handleError(w, r, a.GetID(), provider.Config().ID, nil, err) | ||
return | ||
} | ||
|
||
s.processRegistration(w, r, aa, claims, provider) | ||
return | ||
} | ||
|
||
s.handleError(w, r, a.GetID(), provider.Config().ID, nil, err) | ||
return | ||
} | ||
|
||
var o CredentialsConfig | ||
if err := json.NewDecoder(bytes.NewBuffer(c.Config)).Decode(&o); err != nil { | ||
s.handleError(w, r, a.GetID(), provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("The password credentials could not be decoded properly").WithDebug(err.Error()))) | ||
return | ||
} | ||
|
||
for _, c := range o.Providers { | ||
if c.Subject == claims.Subject && c.Provider == provider.Config().ID { | ||
if err = s.d.LoginHookExecutor().PostLoginHook(w, r, identity.CredentialsTypeOIDC, a, i); err != nil { | ||
s.handleError(w, r, a.GetID(), provider.Config().ID, nil, err) | ||
return | ||
} | ||
return | ||
} | ||
} | ||
|
||
s.handleError(w, r, a.GetID(), provider.Config().ID, nil, errors.WithStack(herodot.ErrInternalServerError.WithReason("Unable to find matching OpenID Connect Credentials.").WithDebugf(`Unable to find credentials that match the given provider "%s" and subject "%s".`, provider.Config().ID, claims.Subject))) | ||
} |
Oops, something went wrong.