Merge pull request #1566 from dexidp/preferred_username
add preffered_username to idToken
This commit is contained in:
commit
d5d3abca6a
12 changed files with 160 additions and 113 deletions
22
README.md
22
README.md
|
@ -63,17 +63,17 @@ Depending on the connectors limitations in protocols can prevent dex from issuin
|
||||||
|
|
||||||
Dex implements the following connectors:
|
Dex implements the following connectors:
|
||||||
|
|
||||||
| Name | supports refresh tokens | supports groups claim | status | notes |
|
| Name | supports refresh tokens | supports groups claim | supports preferred_username claim | status | notes |
|
||||||
| ---- | ----------------------- | --------------------- | ------ | ----- |
|
| ---- | ----------------------- | --------------------- | --------------------------------- | ------ | ----- |
|
||||||
| [LDAP](Documentation/connectors/ldap.md) | yes | yes | stable | |
|
| [LDAP](Documentation/connectors/ldap.md) | yes | yes | yes | stable | |
|
||||||
| [GitHub](Documentation/connectors/github.md) | yes | yes | stable | |
|
| [GitHub](Documentation/connectors/github.md) | yes | yes | yes | stable | |
|
||||||
| [SAML 2.0](Documentation/connectors/saml.md) | no | yes | stable |
|
| [SAML 2.0](Documentation/connectors/saml.md) | no | yes | no | stable |
|
||||||
| [GitLab](Documentation/connectors/gitlab.md) | yes | yes | beta | |
|
| [GitLab](Documentation/connectors/gitlab.md) | yes | yes | yes | beta | |
|
||||||
| [OpenID Connect](Documentation/connectors/oidc.md) | yes | no ([#1065][issue-1065]) | beta | Includes Google, Salesforce, Azure, etc. |
|
| [OpenID Connect](Documentation/connectors/oidc.md) | yes | no ([#1065][issue-1065]) | no | beta | Includes Google, Salesforce, Azure, etc. |
|
||||||
| [LinkedIn](Documentation/connectors/linkedin.md) | yes | no | beta | |
|
| [LinkedIn](Documentation/connectors/linkedin.md) | yes | no | no | beta | |
|
||||||
| [Microsoft](Documentation/connectors/microsoft.md) | yes | yes | beta | |
|
| [Microsoft](Documentation/connectors/microsoft.md) | yes | yes | no | beta | |
|
||||||
| [AuthProxy](Documentation/connectors/authproxy.md) | no | no | alpha | Authentication proxies such as Apache2 mod_auth, etc. |
|
| [AuthProxy](Documentation/connectors/authproxy.md) | no | no | no | alpha | Authentication proxies such as Apache2 mod_auth, etc. |
|
||||||
| [Bitbucket Cloud](Documentation/connectors/bitbucketcloud.md) | yes | yes | alpha | |
|
| [Bitbucket Cloud](Documentation/connectors/bitbucketcloud.md) | yes | yes | no | alpha | |
|
||||||
|
|
||||||
Stable, beta, and alpha are defined as:
|
Stable, beta, and alpha are defined as:
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ type Scopes struct {
|
||||||
|
|
||||||
// Identity represents the ID Token claims supported by the server.
|
// Identity represents the ID Token claims supported by the server.
|
||||||
type Identity struct {
|
type Identity struct {
|
||||||
UserID string
|
UserID string
|
||||||
Username string
|
Username string
|
||||||
Email string
|
PreferredUsername string
|
||||||
EmailVerified bool
|
Email string
|
||||||
|
EmailVerified bool
|
||||||
|
|
||||||
Groups []string
|
Groups []string
|
||||||
|
|
||||||
|
|
|
@ -266,10 +266,11 @@ func (c *githubConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
||||||
}
|
}
|
||||||
|
|
||||||
identity = connector.Identity{
|
identity = connector.Identity{
|
||||||
UserID: strconv.Itoa(user.ID),
|
UserID: strconv.Itoa(user.ID),
|
||||||
Username: username,
|
Username: username,
|
||||||
Email: user.Email,
|
PreferredUsername: user.Login,
|
||||||
EmailVerified: true,
|
Email: user.Email,
|
||||||
|
EmailVerified: true,
|
||||||
}
|
}
|
||||||
if c.useLoginAsID {
|
if c.useLoginAsID {
|
||||||
identity.UserID = user.Login
|
identity.UserID = user.Login
|
||||||
|
@ -317,6 +318,7 @@ func (c *githubConnector) Refresh(ctx context.Context, s connector.Scopes, ident
|
||||||
username = user.Login
|
username = user.Login
|
||||||
}
|
}
|
||||||
identity.Username = username
|
identity.Username = username
|
||||||
|
identity.PreferredUsername = user.Login
|
||||||
identity.Email = user.Email
|
identity.Email = user.Email
|
||||||
|
|
||||||
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
|
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
|
||||||
|
|
|
@ -147,10 +147,11 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
|
||||||
username = user.Email
|
username = user.Email
|
||||||
}
|
}
|
||||||
identity = connector.Identity{
|
identity = connector.Identity{
|
||||||
UserID: strconv.Itoa(user.ID),
|
UserID: strconv.Itoa(user.ID),
|
||||||
Username: username,
|
Username: username,
|
||||||
Email: user.Email,
|
PreferredUsername: user.Username,
|
||||||
EmailVerified: true,
|
Email: user.Email,
|
||||||
|
EmailVerified: true,
|
||||||
}
|
}
|
||||||
if c.useLoginAsID {
|
if c.useLoginAsID {
|
||||||
identity.UserID = user.Username
|
identity.UserID = user.Username
|
||||||
|
@ -197,6 +198,7 @@ func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident
|
||||||
username = user.Email
|
username = user.Email
|
||||||
}
|
}
|
||||||
ident.Username = username
|
ident.Username = username
|
||||||
|
ident.PreferredUsername = user.Username
|
||||||
ident.Email = user.Email
|
ident.Email = user.Email
|
||||||
|
|
||||||
if c.groupsRequired(s.Groups) {
|
if c.groupsRequired(s.Groups) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
// idAttr: uid
|
// idAttr: uid
|
||||||
// emailAttr: mail
|
// emailAttr: mail
|
||||||
// nameAttr: name
|
// nameAttr: name
|
||||||
|
// preferredUsernameAttr: uid
|
||||||
// groupSearch:
|
// groupSearch:
|
||||||
// # Would translate to the query "(&(objectClass=group)(member=<user uid>))"
|
// # Would translate to the query "(&(objectClass=group)(member=<user uid>))"
|
||||||
// baseDN: cn=groups,dc=example,dc=com
|
// baseDN: cn=groups,dc=example,dc=com
|
||||||
|
@ -103,9 +104,10 @@ type Config struct {
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
|
|
||||||
// A mapping of attributes on the user entry to claims.
|
// A mapping of attributes on the user entry to claims.
|
||||||
IDAttr string `json:"idAttr"` // Defaults to "uid"
|
IDAttr string `json:"idAttr"` // Defaults to "uid"
|
||||||
EmailAttr string `json:"emailAttr"` // Defaults to "mail"
|
EmailAttr string `json:"emailAttr"` // Defaults to "mail"
|
||||||
NameAttr string `json:"nameAttr"` // No default.
|
NameAttr string `json:"nameAttr"` // No default.
|
||||||
|
PreferredUsernameAttrAttr string `json:"preferredUsernameAttr"` // No default.
|
||||||
|
|
||||||
// If this is set, the email claim of the id token will be constructed from the idAttr and
|
// If this is set, the email claim of the id token will be constructed from the idAttr and
|
||||||
// value of emailSuffix. This should not include the @ character.
|
// value of emailSuffix. This should not include the @ character.
|
||||||
|
@ -341,6 +343,12 @@ func (c *ldapConnector) identityFromEntry(user ldap.Entry) (ident connector.Iden
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.UserSearch.PreferredUsernameAttrAttr != "" {
|
||||||
|
if ident.PreferredUsername = getAttr(user, c.UserSearch.PreferredUsernameAttrAttr); ident.PreferredUsername == "" {
|
||||||
|
missing = append(missing, c.UserSearch.PreferredUsernameAttrAttr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.UserSearch.EmailSuffix != "" {
|
if c.UserSearch.EmailSuffix != "" {
|
||||||
ident.Email = ident.Username + "@" + c.UserSearch.EmailSuffix
|
ident.Email = ident.Username + "@" + c.UserSearch.EmailSuffix
|
||||||
} else if ident.Email = getAttr(user, c.UserSearch.EmailAttr); ident.Email == "" {
|
} else if ident.Email = getAttr(user, c.UserSearch.EmailAttr); ident.Email == "" {
|
||||||
|
@ -381,6 +389,10 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
|
||||||
req.Attributes = append(req.Attributes, c.UserSearch.NameAttr)
|
req.Attributes = append(req.Attributes, c.UserSearch.NameAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.UserSearch.PreferredUsernameAttrAttr != "" {
|
||||||
|
req.Attributes = append(req.Attributes, c.UserSearch.PreferredUsernameAttrAttr)
|
||||||
|
}
|
||||||
|
|
||||||
c.logger.Infof("performing ldap search %s %s %s",
|
c.logger.Infof("performing ldap search %s %s %s",
|
||||||
req.BaseDN, scopeString(req.Scope), req.Filter)
|
req.BaseDN, scopeString(req.Scope), req.Filter)
|
||||||
resp, err := conn.Search(req)
|
resp, err := conn.Search(req)
|
||||||
|
|
|
@ -479,11 +479,12 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
|
||||||
// the approval page's path.
|
// the approval page's path.
|
||||||
func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.AuthRequest, conn connector.Connector) (string, error) {
|
func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.AuthRequest, conn connector.Connector) (string, error) {
|
||||||
claims := storage.Claims{
|
claims := storage.Claims{
|
||||||
UserID: identity.UserID,
|
UserID: identity.UserID,
|
||||||
Username: identity.Username,
|
Username: identity.Username,
|
||||||
Email: identity.Email,
|
PreferredUsername: identity.PreferredUsername,
|
||||||
EmailVerified: identity.EmailVerified,
|
Email: identity.Email,
|
||||||
Groups: identity.Groups,
|
EmailVerified: identity.EmailVerified,
|
||||||
|
Groups: identity.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
updater := func(a storage.AuthRequest) (storage.AuthRequest, error) {
|
updater := func(a storage.AuthRequest) (storage.AuthRequest, error) {
|
||||||
|
@ -501,8 +502,8 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
|
||||||
email = email + " (unverified)"
|
email = email + " (unverified)"
|
||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Infof("login successful: connector %q, username=%q, email=%q, groups=%q",
|
s.logger.Infof("login successful: connector %q, username=%q, preferred_username=%q, email=%q, groups=%q",
|
||||||
authReq.ConnectorID, claims.Username, email, claims.Groups)
|
authReq.ConnectorID, claims.Username, claims.PreferredUsername, email, claims.Groups)
|
||||||
|
|
||||||
return path.Join(s.issuerURL.Path, "/approval") + "?req=" + authReq.ID, nil
|
return path.Join(s.issuerURL.Path, "/approval") + "?req=" + authReq.ID, nil
|
||||||
}
|
}
|
||||||
|
@ -992,11 +993,12 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||||
}
|
}
|
||||||
|
|
||||||
claims := storage.Claims{
|
claims := storage.Claims{
|
||||||
UserID: ident.UserID,
|
UserID: ident.UserID,
|
||||||
Username: ident.Username,
|
Username: ident.Username,
|
||||||
Email: ident.Email,
|
PreferredUsername: ident.PreferredUsername,
|
||||||
EmailVerified: ident.EmailVerified,
|
Email: ident.Email,
|
||||||
Groups: ident.Groups,
|
EmailVerified: ident.EmailVerified,
|
||||||
|
Groups: ident.Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, err := s.newAccessToken(client.ID, claims, scopes, refresh.Nonce, refresh.ConnectorID)
|
accessToken, err := s.newAccessToken(client.ID, claims, scopes, refresh.Nonce, refresh.ConnectorID)
|
||||||
|
|
|
@ -258,7 +258,8 @@ type idTokenClaims struct {
|
||||||
|
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
PreferredUsername string `json:"preferred_username,omitempty"`
|
||||||
|
|
||||||
FederatedIDClaims *federatedIDClaims `json:"federated_claims,omitempty"`
|
FederatedIDClaims *federatedIDClaims `json:"federated_claims,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -329,6 +330,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
|
||||||
tok.Groups = claims.Groups
|
tok.Groups = claims.Groups
|
||||||
case scope == scopeProfile:
|
case scope == scopeProfile:
|
||||||
tok.Name = claims.Username
|
tok.Name = claims.Username
|
||||||
|
tok.PreferredUsername = claims.PreferredUsername
|
||||||
case scope == scopeFederatedID:
|
case scope == scopeFederatedID:
|
||||||
tok.FederatedIDClaims = &federatedIDClaims{
|
tok.FederatedIDClaims = &federatedIDClaims{
|
||||||
ConnectorID: connID,
|
ConnectorID: connID,
|
||||||
|
|
|
@ -148,30 +148,33 @@ func fromStorageRefreshToken(r storage.RefreshToken) RefreshToken {
|
||||||
|
|
||||||
// Claims is a mirrored struct from storage with JSON struct tags.
|
// Claims is a mirrored struct from storage with JSON struct tags.
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
PreferredUsername string `json:"preferredUsername"`
|
||||||
EmailVerified bool `json:"emailVerified"`
|
Email string `json:"email"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
EmailVerified bool `json:"emailVerified"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromStorageClaims(i storage.Claims) Claims {
|
func fromStorageClaims(i storage.Claims) Claims {
|
||||||
return Claims{
|
return Claims{
|
||||||
UserID: i.UserID,
|
UserID: i.UserID,
|
||||||
Username: i.Username,
|
Username: i.Username,
|
||||||
Email: i.Email,
|
PreferredUsername: i.PreferredUsername,
|
||||||
EmailVerified: i.EmailVerified,
|
Email: i.Email,
|
||||||
Groups: i.Groups,
|
EmailVerified: i.EmailVerified,
|
||||||
|
Groups: i.Groups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toStorageClaims(i Claims) storage.Claims {
|
func toStorageClaims(i Claims) storage.Claims {
|
||||||
return storage.Claims{
|
return storage.Claims{
|
||||||
UserID: i.UserID,
|
UserID: i.UserID,
|
||||||
Username: i.Username,
|
Username: i.Username,
|
||||||
Email: i.Email,
|
PreferredUsername: i.PreferredUsername,
|
||||||
EmailVerified: i.EmailVerified,
|
Email: i.Email,
|
||||||
Groups: i.Groups,
|
EmailVerified: i.EmailVerified,
|
||||||
|
Groups: i.Groups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,30 +210,33 @@ func toStorageClient(c Client) storage.Client {
|
||||||
|
|
||||||
// Claims is a mirrored struct from storage with JSON struct tags.
|
// Claims is a mirrored struct from storage with JSON struct tags.
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
PreferredUsername string `json:"preferredUsername"`
|
||||||
EmailVerified bool `json:"emailVerified"`
|
Email string `json:"email"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
EmailVerified bool `json:"emailVerified"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromStorageClaims(i storage.Claims) Claims {
|
func fromStorageClaims(i storage.Claims) Claims {
|
||||||
return Claims{
|
return Claims{
|
||||||
UserID: i.UserID,
|
UserID: i.UserID,
|
||||||
Username: i.Username,
|
Username: i.Username,
|
||||||
Email: i.Email,
|
PreferredUsername: i.PreferredUsername,
|
||||||
EmailVerified: i.EmailVerified,
|
Email: i.Email,
|
||||||
Groups: i.Groups,
|
EmailVerified: i.EmailVerified,
|
||||||
|
Groups: i.Groups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toStorageClaims(i Claims) storage.Claims {
|
func toStorageClaims(i Claims) storage.Claims {
|
||||||
return storage.Claims{
|
return storage.Claims{
|
||||||
UserID: i.UserID,
|
UserID: i.UserID,
|
||||||
Username: i.Username,
|
Username: i.Username,
|
||||||
Email: i.Email,
|
PreferredUsername: i.PreferredUsername,
|
||||||
EmailVerified: i.EmailVerified,
|
Email: i.Email,
|
||||||
Groups: i.Groups,
|
EmailVerified: i.EmailVerified,
|
||||||
|
Groups: i.Groups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,19 +108,19 @@ func (c *conn) CreateAuthRequest(a storage.AuthRequest) error {
|
||||||
insert into auth_request (
|
insert into auth_request (
|
||||||
id, client_id, response_types, scopes, redirect_uri, nonce, state,
|
id, client_id, response_types, scopes, redirect_uri, nonce, state,
|
||||||
force_approval_prompt, logged_in,
|
force_approval_prompt, logged_in,
|
||||||
claims_user_id, claims_username, claims_email, claims_email_verified,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
expiry
|
expiry
|
||||||
)
|
)
|
||||||
values (
|
values (
|
||||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18
|
||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
a.ID, a.ClientID, encoder(a.ResponseTypes), encoder(a.Scopes), a.RedirectURI, a.Nonce, a.State,
|
a.ID, a.ClientID, encoder(a.ResponseTypes), encoder(a.Scopes), a.RedirectURI, a.Nonce, a.State,
|
||||||
a.ForceApprovalPrompt, a.LoggedIn,
|
a.ForceApprovalPrompt, a.LoggedIn,
|
||||||
a.Claims.UserID, a.Claims.Username, a.Claims.Email, a.Claims.EmailVerified,
|
a.Claims.UserID, a.Claims.Username, a.Claims.PreferredUsername,
|
||||||
encoder(a.Claims.Groups),
|
a.Claims.Email, a.Claims.EmailVerified, encoder(a.Claims.Groups),
|
||||||
a.ConnectorID, a.ConnectorData,
|
a.ConnectorID, a.ConnectorData,
|
||||||
a.Expiry,
|
a.Expiry,
|
||||||
)
|
)
|
||||||
|
@ -149,16 +149,17 @@ func (c *conn) UpdateAuthRequest(id string, updater func(a storage.AuthRequest)
|
||||||
set
|
set
|
||||||
client_id = $1, response_types = $2, scopes = $3, redirect_uri = $4,
|
client_id = $1, response_types = $2, scopes = $3, redirect_uri = $4,
|
||||||
nonce = $5, state = $6, force_approval_prompt = $7, logged_in = $8,
|
nonce = $5, state = $6, force_approval_prompt = $7, logged_in = $8,
|
||||||
claims_user_id = $9, claims_username = $10, claims_email = $11,
|
claims_user_id = $9, claims_username = $10, claims_preferred_username = $11,
|
||||||
claims_email_verified = $12,
|
claims_email = $12, claims_email_verified = $13,
|
||||||
claims_groups = $13,
|
claims_groups = $14,
|
||||||
connector_id = $14, connector_data = $15,
|
connector_id = $15, connector_data = $16,
|
||||||
expiry = $16
|
expiry = $17
|
||||||
where id = $17;
|
where id = $18;
|
||||||
`,
|
`,
|
||||||
a.ClientID, encoder(a.ResponseTypes), encoder(a.Scopes), a.RedirectURI, a.Nonce, a.State,
|
a.ClientID, encoder(a.ResponseTypes), encoder(a.Scopes), a.RedirectURI, a.Nonce, a.State,
|
||||||
a.ForceApprovalPrompt, a.LoggedIn,
|
a.ForceApprovalPrompt, a.LoggedIn,
|
||||||
a.Claims.UserID, a.Claims.Username, a.Claims.Email, a.Claims.EmailVerified,
|
a.Claims.UserID, a.Claims.Username, a.Claims.PreferredUsername,
|
||||||
|
a.Claims.Email, a.Claims.EmailVerified,
|
||||||
encoder(a.Claims.Groups),
|
encoder(a.Claims.Groups),
|
||||||
a.ConnectorID, a.ConnectorData,
|
a.ConnectorID, a.ConnectorData,
|
||||||
a.Expiry, r.ID,
|
a.Expiry, r.ID,
|
||||||
|
@ -180,14 +181,15 @@ func getAuthRequest(q querier, id string) (a storage.AuthRequest, err error) {
|
||||||
select
|
select
|
||||||
id, client_id, response_types, scopes, redirect_uri, nonce, state,
|
id, client_id, response_types, scopes, redirect_uri, nonce, state,
|
||||||
force_approval_prompt, logged_in,
|
force_approval_prompt, logged_in,
|
||||||
claims_user_id, claims_username, claims_email, claims_email_verified,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data, expiry
|
connector_id, connector_data, expiry
|
||||||
from auth_request where id = $1;
|
from auth_request where id = $1;
|
||||||
`, id).Scan(
|
`, id).Scan(
|
||||||
&a.ID, &a.ClientID, decoder(&a.ResponseTypes), decoder(&a.Scopes), &a.RedirectURI, &a.Nonce, &a.State,
|
&a.ID, &a.ClientID, decoder(&a.ResponseTypes), decoder(&a.Scopes), &a.RedirectURI, &a.Nonce, &a.State,
|
||||||
&a.ForceApprovalPrompt, &a.LoggedIn,
|
&a.ForceApprovalPrompt, &a.LoggedIn,
|
||||||
&a.Claims.UserID, &a.Claims.Username, &a.Claims.Email, &a.Claims.EmailVerified,
|
&a.Claims.UserID, &a.Claims.Username, &a.Claims.PreferredUsername,
|
||||||
|
&a.Claims.Email, &a.Claims.EmailVerified,
|
||||||
decoder(&a.Claims.Groups),
|
decoder(&a.Claims.Groups),
|
||||||
&a.ConnectorID, &a.ConnectorData, &a.Expiry,
|
&a.ConnectorID, &a.ConnectorData, &a.Expiry,
|
||||||
)
|
)
|
||||||
|
@ -204,16 +206,16 @@ func (c *conn) CreateAuthCode(a storage.AuthCode) error {
|
||||||
_, err := c.Exec(`
|
_, err := c.Exec(`
|
||||||
insert into auth_code (
|
insert into auth_code (
|
||||||
id, client_id, scopes, nonce, redirect_uri,
|
id, client_id, scopes, nonce, redirect_uri,
|
||||||
claims_user_id, claims_username,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_email, claims_email_verified, claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
expiry
|
expiry
|
||||||
)
|
)
|
||||||
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
|
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
|
||||||
`,
|
`,
|
||||||
a.ID, a.ClientID, encoder(a.Scopes), a.Nonce, a.RedirectURI, a.Claims.UserID,
|
a.ID, a.ClientID, encoder(a.Scopes), a.Nonce, a.RedirectURI, a.Claims.UserID,
|
||||||
a.Claims.Username, a.Claims.Email, a.Claims.EmailVerified, encoder(a.Claims.Groups),
|
a.Claims.Username, a.Claims.PreferredUsername, a.Claims.Email, a.Claims.EmailVerified,
|
||||||
a.ConnectorID, a.ConnectorData, a.Expiry,
|
encoder(a.Claims.Groups), a.ConnectorID, a.ConnectorData, a.Expiry,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -229,15 +231,15 @@ func (c *conn) GetAuthCode(id string) (a storage.AuthCode, err error) {
|
||||||
err = c.QueryRow(`
|
err = c.QueryRow(`
|
||||||
select
|
select
|
||||||
id, client_id, scopes, nonce, redirect_uri,
|
id, client_id, scopes, nonce, redirect_uri,
|
||||||
claims_user_id, claims_username,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_email, claims_email_verified, claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
expiry
|
expiry
|
||||||
from auth_code where id = $1;
|
from auth_code where id = $1;
|
||||||
`, id).Scan(
|
`, id).Scan(
|
||||||
&a.ID, &a.ClientID, decoder(&a.Scopes), &a.Nonce, &a.RedirectURI, &a.Claims.UserID,
|
&a.ID, &a.ClientID, decoder(&a.Scopes), &a.Nonce, &a.RedirectURI, &a.Claims.UserID,
|
||||||
&a.Claims.Username, &a.Claims.Email, &a.Claims.EmailVerified, decoder(&a.Claims.Groups),
|
&a.Claims.Username, &a.Claims.PreferredUsername, &a.Claims.Email, &a.Claims.EmailVerified,
|
||||||
&a.ConnectorID, &a.ConnectorData, &a.Expiry,
|
decoder(&a.Claims.Groups), &a.ConnectorID, &a.ConnectorData, &a.Expiry,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
@ -252,15 +254,16 @@ func (c *conn) CreateRefresh(r storage.RefreshToken) error {
|
||||||
_, err := c.Exec(`
|
_, err := c.Exec(`
|
||||||
insert into refresh_token (
|
insert into refresh_token (
|
||||||
id, client_id, scopes, nonce,
|
id, client_id, scopes, nonce,
|
||||||
claims_user_id, claims_username, claims_email, claims_email_verified,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
token, created_at, last_used
|
token, created_at, last_used
|
||||||
)
|
)
|
||||||
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
|
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
|
||||||
`,
|
`,
|
||||||
r.ID, r.ClientID, encoder(r.Scopes), r.Nonce,
|
r.ID, r.ClientID, encoder(r.Scopes), r.Nonce,
|
||||||
r.Claims.UserID, r.Claims.Username, r.Claims.Email, r.Claims.EmailVerified,
|
r.Claims.UserID, r.Claims.Username, r.Claims.PreferredUsername,
|
||||||
|
r.Claims.Email, r.Claims.EmailVerified,
|
||||||
encoder(r.Claims.Groups),
|
encoder(r.Claims.Groups),
|
||||||
r.ConnectorID, r.ConnectorData,
|
r.ConnectorID, r.ConnectorData,
|
||||||
r.Token, r.CreatedAt, r.LastUsed,
|
r.Token, r.CreatedAt, r.LastUsed,
|
||||||
|
@ -291,19 +294,21 @@ func (c *conn) UpdateRefreshToken(id string, updater func(old storage.RefreshTok
|
||||||
nonce = $3,
|
nonce = $3,
|
||||||
claims_user_id = $4,
|
claims_user_id = $4,
|
||||||
claims_username = $5,
|
claims_username = $5,
|
||||||
claims_email = $6,
|
claims_preferred_username = $6,
|
||||||
claims_email_verified = $7,
|
claims_email = $7,
|
||||||
claims_groups = $8,
|
claims_email_verified = $8,
|
||||||
connector_id = $9,
|
claims_groups = $9,
|
||||||
connector_data = $10,
|
connector_id = $10,
|
||||||
token = $11,
|
connector_data = $11,
|
||||||
created_at = $12,
|
token = $12,
|
||||||
last_used = $13
|
created_at = $13,
|
||||||
|
last_used = $14
|
||||||
where
|
where
|
||||||
id = $14
|
id = $15
|
||||||
`,
|
`,
|
||||||
r.ClientID, encoder(r.Scopes), r.Nonce,
|
r.ClientID, encoder(r.Scopes), r.Nonce,
|
||||||
r.Claims.UserID, r.Claims.Username, r.Claims.Email, r.Claims.EmailVerified,
|
r.Claims.UserID, r.Claims.Username, r.Claims.PreferredUsername,
|
||||||
|
r.Claims.Email, r.Claims.EmailVerified,
|
||||||
encoder(r.Claims.Groups),
|
encoder(r.Claims.Groups),
|
||||||
r.ConnectorID, r.ConnectorData,
|
r.ConnectorID, r.ConnectorData,
|
||||||
r.Token, r.CreatedAt, r.LastUsed, id,
|
r.Token, r.CreatedAt, r.LastUsed, id,
|
||||||
|
@ -323,7 +328,8 @@ func getRefresh(q querier, id string) (storage.RefreshToken, error) {
|
||||||
return scanRefresh(q.QueryRow(`
|
return scanRefresh(q.QueryRow(`
|
||||||
select
|
select
|
||||||
id, client_id, scopes, nonce,
|
id, client_id, scopes, nonce,
|
||||||
claims_user_id, claims_username, claims_email, claims_email_verified,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
|
claims_email, claims_email_verified,
|
||||||
claims_groups,
|
claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
token, created_at, last_used
|
token, created_at, last_used
|
||||||
|
@ -335,8 +341,8 @@ func (c *conn) ListRefreshTokens() ([]storage.RefreshToken, error) {
|
||||||
rows, err := c.Query(`
|
rows, err := c.Query(`
|
||||||
select
|
select
|
||||||
id, client_id, scopes, nonce,
|
id, client_id, scopes, nonce,
|
||||||
claims_user_id, claims_username, claims_email, claims_email_verified,
|
claims_user_id, claims_username, claims_preferred_username,
|
||||||
claims_groups,
|
claims_email, claims_email_verified, claims_groups,
|
||||||
connector_id, connector_data,
|
connector_id, connector_data,
|
||||||
token, created_at, last_used
|
token, created_at, last_used
|
||||||
from refresh_token;
|
from refresh_token;
|
||||||
|
@ -361,7 +367,8 @@ func (c *conn) ListRefreshTokens() ([]storage.RefreshToken, error) {
|
||||||
func scanRefresh(s scanner) (r storage.RefreshToken, err error) {
|
func scanRefresh(s scanner) (r storage.RefreshToken, err error) {
|
||||||
err = s.Scan(
|
err = s.Scan(
|
||||||
&r.ID, &r.ClientID, decoder(&r.Scopes), &r.Nonce,
|
&r.ID, &r.ClientID, decoder(&r.Scopes), &r.Nonce,
|
||||||
&r.Claims.UserID, &r.Claims.Username, &r.Claims.Email, &r.Claims.EmailVerified,
|
&r.Claims.UserID, &r.Claims.Username, &r.Claims.PreferredUsername,
|
||||||
|
&r.Claims.Email, &r.Claims.EmailVerified,
|
||||||
decoder(&r.Claims.Groups),
|
decoder(&r.Claims.Groups),
|
||||||
&r.ConnectorID, &r.ConnectorData,
|
&r.ConnectorID, &r.ConnectorData,
|
||||||
&r.Token, &r.CreatedAt, &r.LastUsed,
|
&r.Token, &r.CreatedAt, &r.LastUsed,
|
||||||
|
|
|
@ -190,4 +190,16 @@ var migrations = []migration{
|
||||||
);`,
|
);`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
stmts: []string{`
|
||||||
|
alter table auth_code
|
||||||
|
add column claims_preferred_username text not null default '';`,
|
||||||
|
`
|
||||||
|
alter table auth_request
|
||||||
|
add column claims_preferred_username text not null default '';`,
|
||||||
|
`
|
||||||
|
alter table refresh_token
|
||||||
|
add column claims_preferred_username text not null default '';`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,10 +137,11 @@ type Client struct {
|
||||||
|
|
||||||
// Claims represents the ID Token claims supported by the server.
|
// Claims represents the ID Token claims supported by the server.
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
UserID string
|
UserID string
|
||||||
Username string
|
Username string
|
||||||
Email string
|
PreferredUsername string
|
||||||
EmailVerified bool
|
Email string
|
||||||
|
EmailVerified bool
|
||||||
|
|
||||||
Groups []string
|
Groups []string
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue