SAML authentication providers (Legacy)
The Maverics Orchestrator can be configured to act as a SAML Identity Provider. Using the Orchestrator as a SAML-based IDP can be useful when existing applications authenticate via SAML or when identity needs to be asserted into another system such as a legacy IDP.
Name
The name
value must be a unique name for each SAMLProvider instance.
Type
The type
of identity protocol, saml
, that will be used.
Attribute Providers
An optional configuration for an identity system or data store from which the SAMLProvider may retrieve additional attributes used in claimsMapping
.
Connector
Connector is a reference to the name of the defined connector which will be used as an attribute provider.
usernameMapping
usernameMapping
defines the attribute that will be used as a search key to query for the user’s attributes.
MetadataEndpoint
The metadataEndpoint
is the URL which this SAML server serves its metadata file from.
This is an optional configuration, if left unset connecting Service Providers will need to be manually configured.
Single Sign On Service Endpoint
The singleSignOnServiceEndpoint
is the location of where service providers will send SAML
authentication requests.
Single Logout Service Endpoint
The singleLogoutServiceEndpoint
is an optional field that defines
the location of where service providers will send SAML logout requests.
Issuer
issuer
is the IDP who issues SAML assertions. This value is usually a URL.
Signature
signature
is the configuration to sign SAML responses.
Certificate
certificate
the x509 certificate used by clients to validate the signature of SAML assertions.
Private Key
privateKey
is the RSA256 private key used to sign SAML assertions.
Disable Signing Response
disableSignedResponse
optional field that allows you to override signing the response by default. Default is false. Note that either the Response or Assertion must be signed.
Disable Signing Assertion
disableSignedAssertion
optional field that allows you to override signing the assertion by default. Default is false. Note that either the Response or Assertion must be signed.
Clients
clients
represent the registered SAML clients (AKA Service Providers and Relying Parties).
Name
A unique name
identifier for the client.
Audience
audience
denotes who the client is. It should match the Issuer field provided by the service provider. This value must be unique.
Consumer Service URL
consumerServiceURL
is the URL where SAML responses will be sent.
Duration
The duration
in seconds which this server’s responses are valid for.
NameID Format
nameIDFormat
is an optional field used to define the NameID Format that will be used
in the SAML assertion. When not defined, a value of
'urn:oasis:names:tc:SAML:1.0:nameid-format:unspecified'
will be used. If a
NameIDPolicy is defined on the SAML Authentication request, it must match the
NameID Format defined on the client. For more details on NameID Format, please see
section 2.2, 3.4.1, and 8.3 of the SAML spec.
Request Verification
requestVerification
is a mandatory configuration, and it will either hold the public key used to validate the signature of incoming requests, or it will disable request signing verification.
Certificate
certificate
is the RSA x509 certificate, and will be used to verify the signatures of incoming requests. It may be defined inline or with a secret provider. It must be RSA compatible. Currently this auth provider only supports SHA-256 for request signing and digest algorithm.
requestVerification:
certificate: |+
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
requestVerification:
certificate: <clientSigningCert>
Skip Verification
skipVerification
is a boolean value and is used when the client does not want to validate the signatures of incoming requests.
requestVerification:
skipVerification: true
Authentication with IDPs
The authentication
field provides a way to list the idps
that will be used to authenticate a user.
In the example below, the user will be prompted to authenticate with Azure first and then Okta.
authproviders:
- name: saml
type: samlAuthProvider
# ...
clients:
- name: ExampleClient
# ...
authentication:
idps:
- azure
- okta
AttrProviders
An optional configuration for an identity system or data store from which the SAMLProvider may retrieve additional attributes used in claimsMapping
.
This client level configuration will override any provider level configuration.
Connector
Connector is a reference to the name of the defined connector which will be used as an attribute provider.
usernameMapping
The usernameMapping
configuration makes sure the Attribute Provider (i.e. LDAP Connector) has the correct attribute it needs to successfully query for the user’s attributes.
It specifies the attribute used to look up user attributes from the defined attribute provider.
Assertion
assertion
is the parent category for storing configurations related to the SAML
assertions of the client. If omitted, the assertions for this client will not be
encrypted.
Encryption
encryption
is the configuration category for encrypting the SAML assertion.
Key Encrypt Method
keyEncryptMethod
configures the encryption method for encrypting the symmetric key
which is used to encrypt the assertion. Currently, we support two values here which
are RSA_OAEP
and RSA-1_5.
RSA-1_5
is not recommended according to the
XML encryption spec due to
security risks associated with the algorithm.
Data Encrypt Method
dataEncryptMethod
configures the encryption method for encrypting the actual data
of the assertion. Valid values are AES128CBC
, AES192CBC
, and AES256CBC
.
Digest Method
digestMethod
is the message digest algorithm use to compute a message digest as
part of the encryption process. Valid values are SHA256
, and SHA512
.
Certificate
certificate
under the assertion
section is the PEM encoded string that can be
defined inline or via a secret provider. This certificate is typically retrieved
from the Service Provider. Below is an example of defining the certificate inline.
assertion:
encryption:
keyEncryptMethod: RSA_OAEP
dataEncryptMethod: AES256CBC
digestMethod: SHA256
certificate: |+ # An example of defining the certificate value inline.
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
ClaimsMapping
The claimsMapping
provides a way to provide additional claims to this user. This
maps claims to session attributes provided by the IDP(s) and any optionally defined AttributeProvider(s).
These mapping fields are used to map claims from the connectors back to the
SAML Service Provider in AttributeStatement
as AttributeValue
.
Note that the key name
is used to denote the value which will be used as the Subject of the SAMLResponse.
Example config:
authproviders:
- name: samlAuthProvider
type: saml
# ...
clients:
- name: ExampleClient
# ...
attrProviders:
- connector: ldap
usernameMapping: azure.email
claimsMapping:
name: azure.objectidentifier
email: azure.name
family_name: azure.surname
given_name: azure.givenname
phone: ldap.mobile
IDP Initiated Login
The idpInitiatedLogin
key is an optional configuration which when specified will
enable the auth provider to perform IDP initiated login to the client.
Login URL
loginURL
is the endpoint that the user will visit from their browser to initiate
the IDP login flow. This endpoint needs to be unique on the Orchestrator.
Relay State URL
relayStateURL
is the endpoint that gets passed to the service provider and is
intended to be the landing page for the user after the authentication flow is complete.
authproviders:
- type: saml
# ...
clients:
- name: sonar
# ...
idpInitiatedLogin:
loginURL: https://maverics.sonarsystems.com/login-sonar
relayStateURL: https://app.sonarsystems.com/index.html
Auth Provider and Client level Service Extensions
The below Service Extensions may optionally be defined at the Auth Provider or Client level in order to control the behavior for clients.
isAuthenticatedSE
isAuthenticatedSE
is an optional Service Extension that can be used to override the default behavior that determines if a user is already authenticated.
authproviders:
- name: samlAuthProvider
type: saml
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/auth.go
/etc/maverics/extensions/auth.go
package main
import (
"net/http"
"maverics/auth"
"maverics/session"
)
func IsAuthenticated(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) bool {
if session.GetString(req, "azure.authenticated") == "true" {
return true
}
return false
}
authenticateSE
The authenticateSE
is an optional Service Extension used to take control of how authentication will be done.
authproviders:
- name: saml
type: samlAuthProvider
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/auth.go
# ...
/etc/maverics/extensions/auth.go
package main
import (
"net/http"
"maverics/auth"
)
func Authenticate(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) {
sp.IDPs["azure"].CreateRequest().Login(rw, req)
}
buildClaimsSE
buildClaimsSE
is an optional Service Extension that can customize which attributes
will be shared to the up-stream SAML Service Provider as a SAML 2.0 AttributeStatement.
authproviders:
- name: samlAuthProvider
type: saml
buildClaimsSE:
funcName: BuildClaims
file: /etc/maverics/extensions/buildClaims.go
/etc/maverics/extensions/buildClaims.go
package main
import (
"fmt"
"net/http"
"maverics/auth"
"maverics/log"
"maverics/session"
)
func BuildClaims(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) (map[string]string, error) {
log.Debug("msg", "building custom claims")
email := session.GetString(req, "azure.email")
if email == "" {
return nil, fmt.Errorf("did not find user email on session")
}
returnAttrs := map[string]string{
"email": email,
}
log.Debug(
"msg", "successfully built custom claims",
"claims", fmt.Sprintf("%v", returnAttrs),
)
return returnAttrs, nil
}
Examples
Basic
This example shows the SAML auth provider being defined.
authproviders:
- name: samlAuthProvider
type: saml
metadataEndpoint: https://maverics.com/idp/saml/metadata.xml # Optional endpoint.
singleSignOnServiceEndpoint: https://maverics.com/idp/saml/sso
singleLogoutServiceEndpoint: https://maverics.com/idp/saml/slo # Optional endpoint to enable logout.
issuer: https://maverics.com/idp/
signature:
certificate: |+ # An example of defining the certificate value inline.
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
privateKey: <samlTestPrivateKey> # An example of using a secret provider to load the private key.
disableSignedResponse: false
disableSignedAssertion: false
clients:
- name: exampleClient
audience: https://exampleco.com/
consumerServiceURL: https://exampleco.com/saml/acs
duration: 60
nameIDFormat: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
requestVerification:
skipVerification: true
authentication:
idps:
- azure
attrProviders: # An optional config to support non-idps to be used in claimsMapping.
- connector: ldap
usernameMapping: azure.email
assertion:
encryption:
keyEncryptMethod: RSA_OAEP
dataEncryptMethod: AES256CBC
digestMethod: SHA256
certificate: <encryptionCert>
claimsMapping:
name: azure.username
# Optional claim mappings.
email: azure.name
family_name: azure.surname
given_name: azure.givenname
phone: ldap.mobile
Service Extensions
The below example shows a complete configuration using default implementation, alongside AuthProvider level and client level Service Extension definitions.
authproviders:
- name: samlAuthProvider
type: saml
metadataEndpoint: https://maverics.com/idp/saml/metadata.xml # optional
singleSignOnServiceEndpoint: https://maverics.com/idp/saml/sso
issuer: https://maverics.com/idp/
signature:
certificate: |+ # An example of defining the certificate value inline.
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
privateKey: <samlTestPrivateKey> # An example of using a secret provider to load the private key.
disableSignedResponse: false
disableSignedAssertion: false
# Below are examples of optional Service Extension definitions at the
# AuthProvider level. These will run for clients which do not use `claimsMapping`
# or define their own Service Extensions.
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/authprovider.go
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/authprovider.go
buildClaimsSE:
funcName: BuildClaims
file: /etc/maverics/extensions/authprovider.go
clients:
# An example of a client definition using the default implementations for authentication
# and building attributes.
- name: alphaClient
audience: https://clientapp.com/audience/
consumerServiceURL: https://exampleco.com/saml/acs
duration: 60
requestVerification:
skipVerification: true
authentication:
idps:
- azure
claimsMapping:
name: azure.objectidentifier
email: azure.name
family_name: azure.surname
given_name: azure.givenname
# An example of a client definition which falls back to using the AuthProvider
# level Service Extensions for authentication and building attributes.
- name: betaClient
audience: https://clientapp.com/audience/
consumerServiceURL: https://exampleco.com/saml/acs
duration: 60
requestVerification:
certificate: <fallbackSEClientSigningCert>
# An example of a client definition which uses its own Service Extensions for
# authentication and building attributes.
- name: gammaClient
audience: https://clientapp.com/audience/
consumerServiceURL: https://exampleco.com/saml/acs
duration: 60
requestVerification:
certificate: <seClientSigningCert>
authentication:
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/gammaClient.go
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/gammaClient.go
buildClaimsSE:
funcName: BuildClaims
file: /etc/maverics/extensions/gammaClient.go
/etc/maverics/extensions/authprovider.go
package main
import (
"errors"
"net/http"
"maverics/auth"
"maverics/log"
"maverics/session"
)
func IsAuthenticated(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) bool {
result := session.GetString(req, "azure.authenticated") == "true"
log.Debug(
"msg", "called isAuthnAuthProvider",
"path", req.URL.Path,
"result", result,
)
return result
}
func Authenticate(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) error {
log.Debug("msg", "authenticating user", "path", req.URL.Path)
idp, ok := sp.IDPs["azure"]
if !ok {
return errors.New("missing idp definition for 'azure' in 'idps'")
}
// The IDP exists. Attempt to login and proceed to the authz flow.
log.Debug("msg", "azure IDP exsits, start login", "path", req.URL.Path)
idp.CreateRequest().Login(rw, req)
http.Redirect(rw, req, req.URL.Path, 302)
return nil
}
func BuildClaims(sp *auth.SAMLProvider, rw http.ResponseWriter, req http.Request) (map[string]string, error) {
return map[string]string{
"role": session.GetString("ldap.role"),
}, nil
}
/etc/maverics/extensions/gammaClient.go
package main
import (
"errors"
"net/http"
"maverics/auth"
"maverics/log"
"maverics/session"
)
func IsAuthenticated(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) bool {
result := session.GetString(req, "azure.authenticated") == "true"
log.Debug("msg", "called isAuthnClient",
"path", req.URL.Path,
"result", result)
return result
}
func Authenticate(sp *auth.SAMLProvider, rw http.ResponseWriter, req *http.Request) error {
log.Debug("msg", "authenticating user", "path", req.URL.Path)
idp, ok := sp.IDPs["azure"]
if !ok {
return errors.New("missing idp definition for 'azure' in 'idps'")
}
// The IDP exists. Attempt to login and proceed to the authz flow.
log.Debug("msg", "azure IDP exsits, start login", "path", req.URL.Path)
idp.CreateRequest().Login(rw, req)
http.Redirect(rw, req, req.URL.Path, 302)
return nil
}
func BuildClaims(sp *auth.SAMLProvider, rw http.ResponseWriter, req http.Request) (map[string]string, error) {
return map[string]string{
"role": session.GetString("ldap.role"),
}, nil
}
Limitations
Authn Request
ProtocolBinding
is a URI reference that identifies the SAML protocol binding to be used when returning the Response message. The supported bindings are:urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
SignatureMethod
- SAML assertions and protocols must use enveloped signatures when signing assertions and protocol messages. The SAMLProvider only supportsrsa-sha256
and intentionally does not supportrsa-sha1
since it is cryptographically insecure.