Merge pull request #902 from ericchiang/saml-stable
*: promote SAML to stable
This commit is contained in:
		@@ -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 New Issue
	
	Block a user