Merge pull request #902 from ericchiang/saml-stable
*: promote SAML to stable
This commit is contained in:
commit
c3cafc8f39
6 changed files with 64 additions and 41 deletions
|
@ -12,7 +12,7 @@ The following is the exhaustive list of scopes supported by dex:
|
||||||
| `email` | ID token claims should include the end user's email and if that email was verified by an upstream provider. |
|
| `email` | ID token claims should include the end user's email and if that email was verified by an upstream provider. |
|
||||||
| `profile` | ID token claims should include the username of the end user. |
|
| `profile` | ID token claims should include the username of the end user. |
|
||||||
| `groups` | ID token claims should include a list of groups the end user is a member of. |
|
| `groups` | ID token claims should include a list of groups the end user is a member of. |
|
||||||
| `offline_access` | Token response should include a refresh token. |
|
| `offline_access` | Token response should include a refresh token. Doesn't work in combinations with some connectors, notability the [SAML connector][saml-connector] ignores this scope. |
|
||||||
| `audience:server:client_id:( client-id )` | Dynamic scope indicating that the ID token should be issued on behalf of another client. See the _"Cross-client trust and authorized party"_ section below. |
|
| `audience:server:client_id:( client-id )` | Dynamic scope indicating that the ID token should be issued on behalf of another client. See the _"Cross-client trust and authorized party"_ section below. |
|
||||||
|
|
||||||
## Custom claims
|
## Custom claims
|
||||||
|
@ -67,5 +67,6 @@ The ID token claims will then include the following audience and authorized part
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[saml-connector]: saml-connector.md
|
||||||
[core-claims]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
[core-claims]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||||
[standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
[standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||||
|
|
|
@ -121,7 +121,7 @@ At the app, go to the "Sign On" tab and then click "View Setup Instructions". Us
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
connectors:
|
connectors:
|
||||||
- type: samlExperimental
|
- type: saml
|
||||||
id: saml
|
id: saml
|
||||||
name: Okta
|
name: Okta
|
||||||
config:
|
config:
|
||||||
|
|
|
@ -2,23 +2,23 @@
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The experimental SAML provider allows authentication through the SAML 2.0 HTTP POST binding.
|
The SAML provider allows authentication through the SAML 2.0 HTTP POST binding. The connector maps attribute values in the SAML assertion to user info, such as username, email, and groups.
|
||||||
|
|
||||||
The connector uses the value of the `NameID` element as the user's unique identifier which dex assumes is both unique and never changes. Use the `nameIDPolicyFormat` to ensure this is set to a value which satisfies these requirements.
|
The connector uses the value of the `NameID` element as the user's unique identifier which dex assumes is both unique and never changes. Use the `nameIDPolicyFormat` to ensure this is set to a value which satisfies these requirements.
|
||||||
|
|
||||||
|
Unlike some clients which will process unprompted AuthnResponses, dex must send the initial AuthnRequest and validates the response's InResponseTo value.
|
||||||
|
|
||||||
## Caveats
|
## Caveats
|
||||||
|
|
||||||
There are known issues with the XML signature validation for this connector. In addition work is still being done to ensure this connector implements best security practices for SAML 2.0.
|
__The connector doesn't support refresh tokens__ since the SAML 2.0 protocol doesn't provide a way to requery a provider without interaction. If the "offline_access" scope is requested, it will be ignored.
|
||||||
|
|
||||||
The connector doesn't support signed AuthnRequests or encrypted attributes.
|
The connector doesn't support signed AuthnRequests or encrypted attributes.
|
||||||
|
|
||||||
The connector doesn't support refresh tokens since the SAML 2.0 protocol doesn't provide a way to requery a provider without interaction. Ensure that the "offline_access" scope is not requested in client apps.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
connectors:
|
connectors:
|
||||||
- type: samlExperimental # will be changed to "saml" later without support for the "samlExperimental" value
|
- type: saml
|
||||||
# Required field for connector id.
|
# Required field for connector id.
|
||||||
id: saml
|
id: saml
|
||||||
# Required field for connector name.
|
# Required field for connector name.
|
||||||
|
@ -27,9 +27,23 @@ connectors:
|
||||||
# SSO URL used for POST value.
|
# SSO URL used for POST value.
|
||||||
ssoURL: https://saml.example.com/sso
|
ssoURL: https://saml.example.com/sso
|
||||||
|
|
||||||
# CA to use when validating the SAML response.
|
# CA to use when validating the signature of the SAML response.
|
||||||
ca: /path/to/ca.pem
|
ca: /path/to/ca.pem
|
||||||
|
|
||||||
|
# Dex's callback URL.
|
||||||
|
#
|
||||||
|
# If the response assertion status value contains a Destination element, it
|
||||||
|
# must match this value exactly.
|
||||||
|
#
|
||||||
|
# This is also used as the expected audience for AudienceRestriction elements
|
||||||
|
# if entityIssuer isn't specified.
|
||||||
|
redirectURI: https://dex.example.com/callback
|
||||||
|
|
||||||
|
# Name of attributes in the returned assertions to map to ID token claims.
|
||||||
|
usernameAttr: name
|
||||||
|
emailAttr: email
|
||||||
|
groupsAttr: groups # optional
|
||||||
|
|
||||||
# CA's can also be provided inline as a base64'd blob.
|
# CA's can also be provided inline as a base64'd blob.
|
||||||
#
|
#
|
||||||
# caData: ( RAW base64'd PEM encoded CA )
|
# caData: ( RAW base64'd PEM encoded CA )
|
||||||
|
@ -39,37 +53,31 @@ connectors:
|
||||||
#
|
#
|
||||||
# insecureSkipSignatureValidation: true
|
# insecureSkipSignatureValidation: true
|
||||||
|
|
||||||
# Optional: Issuer value for AuthnRequest
|
# Optional: Manually specify dex's Issuer value.
|
||||||
# Must be contained within the "AudienceRestriction" attribute in all responses
|
#
|
||||||
# If not set, redirectURI will be used for audience validation
|
# When provided dex will include this as the Issuer value during AuthnRequest.
|
||||||
|
# It will also override the redirectURI as the required audience when evaluating
|
||||||
|
# AudienceRestriction elements in the response.
|
||||||
entityIssuer: https://dex.example.com/callback
|
entityIssuer: https://dex.example.com/callback
|
||||||
|
|
||||||
# Optional: Issuer value for SAML Response
|
# Optional: Issuer value expected in the SAML response.
|
||||||
ssoIssuer: https://saml.example.com/sso
|
ssoIssuer: https://saml.example.com/sso
|
||||||
|
|
||||||
# Dex's callback URL. Must match the "Destination" attribute of all responses
|
# Optional: Delimiter for splitting groups returned as a single string.
|
||||||
# exactly.
|
#
|
||||||
redirectURI: https://dex.example.com/callback
|
|
||||||
|
|
||||||
# Name of attributes in the returned assertions to map to ID token claims.
|
|
||||||
usernameAttr: name
|
|
||||||
emailAttr: email
|
|
||||||
groupsAttr: groups # optional
|
|
||||||
|
|
||||||
# By default, multiple groups are assumed to be represented as multiple
|
# By default, multiple groups are assumed to be represented as multiple
|
||||||
# attributes with the same name.
|
# attributes with the same name.
|
||||||
#
|
#
|
||||||
# If "groupsDelim" is provided groups are assumed to be represented as a
|
# If "groupsDelim" is provided groups are assumed to be represented as a
|
||||||
# single attribute and the delimiter is used to split the attribute's value
|
# single attribute and the delimiter is used to split the attribute's value
|
||||||
# into multiple groups.
|
# into multiple groups.
|
||||||
|
groupsDelim: ", "
|
||||||
|
|
||||||
|
# Optional: Requested format of the NameID.
|
||||||
#
|
#
|
||||||
# groupsDelim: ", "
|
# The NameID value is is mapped to the user ID of the user. This can be an
|
||||||
|
# abbreviated form of the full URI with just the last component. For example,
|
||||||
|
# if this value is set to "emailAddress" the format will resolve to:
|
||||||
# Requested format of the NameID. The NameID value is is mapped to the ID Token
|
|
||||||
# 'sub' claim. This can be an abbreviated form of the full URI with just the last
|
|
||||||
# component. For example, if this value is set to "emailAddress" the format will
|
|
||||||
# resolve to:
|
|
||||||
#
|
#
|
||||||
# urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
# urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
#
|
#
|
||||||
|
@ -78,8 +86,20 @@ connectors:
|
||||||
# urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
# urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
|
||||||
#
|
#
|
||||||
nameIDPolicyFormat: persistent
|
nameIDPolicyFormat: persistent
|
||||||
|
```
|
||||||
# Optional issuer used for validating the SAML response. If provided the
|
|
||||||
# connector will validate the Issuer in the response.
|
A minimal working configuration might look like:
|
||||||
# issuer: https://saml.example.com
|
|
||||||
|
```yaml
|
||||||
|
connectors:
|
||||||
|
- type: saml
|
||||||
|
id: okta
|
||||||
|
name: Okta
|
||||||
|
config:
|
||||||
|
ssoURL: https://dev-111102.oktapreview.com/app/foo/exk91cb99lKkKSYoy0h7/sso/saml
|
||||||
|
ca: /etc/dex/saml-ca.pem
|
||||||
|
redirectURI: http://127.0.0.1:5556/dex/callback
|
||||||
|
usernameAttr: name
|
||||||
|
emailAttr: email
|
||||||
|
groupsAttr: groups
|
||||||
```
|
```
|
||||||
|
|
|
@ -39,7 +39,7 @@ More docs for running dex as a Kubernetes authenticator can be found [here](Docu
|
||||||
* [LDAP](Documentation/ldap-connector.md)
|
* [LDAP](Documentation/ldap-connector.md)
|
||||||
* [GitHub](Documentation/github-connector.md)
|
* [GitHub](Documentation/github-connector.md)
|
||||||
* [GitLab](Documentation/gitlab-connector.md)
|
* [GitLab](Documentation/gitlab-connector.md)
|
||||||
* [SAML 2.0 (experimental)](Documentation/saml-connector.md)
|
* [SAML 2.0](Documentation/saml-connector.md)
|
||||||
* [OpenID Connect](Documentation/oidc-connector.md) (includes Google, Salesforce, Azure, etc.)
|
* [OpenID Connect](Documentation/oidc-connector.md) (includes Google, Salesforce, Azure, etc.)
|
||||||
* Client libraries
|
* Client libraries
|
||||||
* [Go][go-oidc]
|
* [Go][go-oidc]
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
"github.com/coreos/dex/connector/github"
|
"github.com/coreos/dex/connector/github"
|
||||||
"github.com/coreos/dex/connector/gitlab"
|
"github.com/coreos/dex/connector/gitlab"
|
||||||
|
@ -179,12 +179,14 @@ type ConnectorConfig interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
var connectors = map[string]func() ConnectorConfig{
|
var connectors = map[string]func() ConnectorConfig{
|
||||||
"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
|
"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
|
||||||
"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
|
"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
|
||||||
"ldap": func() ConnectorConfig { return new(ldap.Config) },
|
"ldap": func() ConnectorConfig { return new(ldap.Config) },
|
||||||
"github": func() ConnectorConfig { return new(github.Config) },
|
"github": func() ConnectorConfig { return new(github.Config) },
|
||||||
"gitlab": func() ConnectorConfig { return new(gitlab.Config) },
|
"gitlab": func() ConnectorConfig { return new(gitlab.Config) },
|
||||||
"oidc": func() ConnectorConfig { return new(oidc.Config) },
|
"oidc": func() ConnectorConfig { return new(oidc.Config) },
|
||||||
|
"saml": func() ConnectorConfig { return new(saml.Config) },
|
||||||
|
// Keep around for backwards compatibility.
|
||||||
"samlExperimental": func() ConnectorConfig { return new(saml.Config) },
|
"samlExperimental": func() ConnectorConfig { return new(saml.Config) },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -648,7 +648,7 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
|
||||||
reqRefresh := func() bool {
|
reqRefresh := func() bool {
|
||||||
// Ensure the connector supports refresh tokens.
|
// Ensure the connector supports refresh tokens.
|
||||||
//
|
//
|
||||||
// Connectors like `samlExperimental` do not implement RefreshConnector.
|
// Connectors like `saml` do not implement RefreshConnector.
|
||||||
conn, ok := s.connectors[authCode.ConnectorID]
|
conn, ok := s.connectors[authCode.ConnectorID]
|
||||||
if !ok {
|
if !ok {
|
||||||
s.logger.Errorf("connector ID not found: %q", authCode.ConnectorID)
|
s.logger.Errorf("connector ID not found: %q", authCode.ConnectorID)
|
||||||
|
|
Reference in a new issue