Applications SAML
L’orchestrateur d’identité Maverics peut être utilisé en tant que fournisseur d’identité pour protéger les applications SAML.
samlProvider
doit être définie.Options de configuration
Name
name
est un identifiant unique pour l’application.
Type
type
représente le type d’application. Lors de la définition des applications SAML, le type
doit être saml
.
Public
audience
correspond à un identifiant unique de l’application. La valeur audience
est généralement une URL, et elle doit correspondre au champ « Issuer » (Émetteur) fourni par le fournisseur de services SAML.
Consumer Service URL
consumerServiceURL
correspond à l’URL vers laquelle les réponses d’authentification SAML sont envoyées.
Logout Service URL
logoutServiceURL
est un champ facultatif qui définit l’URL vers laquelle les réponses de déconnexion SAML
sont envoyées. Ce champ doit être défini si la fonctionnalité de déconnexion est requise.
IDP Initiated Login
La clé idpInitiatedLogin
est une configuration facultative qui, lorsqu’elle est spécifiée,
permet au fournisseur d’authentification d’effectuer la connexion initiée par le fournisseur d’identité au client.
Login URL
loginURL
correspond au terminal consulté par l’utilisateur à partir de son navigateur pour initier
le flux de connexion au fournisseur d’identité. Il doit s’agir de l’unique terminal sur l’orchestrateur.
Relay State URL
relayStateURL
correspond au terminal transmis au fournisseur de services
qui servira de page d’accueil à l’utilisateur à l’issue du flux d’authentification.
Extension de services Build Relay State
buildRelayStateSE
peut être utilisé pour construire le paramètre RelayState
dans un
flux de connexion initié par le fournisseur d’identité. Cette extension peut être utilisée lorsque l’état du relais est dynamique
et ne peut donc pas être défini avec un relayStateURL
statique.
Durée
duration
correspond à la durée en secondes pendant laquelle les assertions SAML sont valides. Si aucune valeur
n’est définie, une durée de cinq minutes (300 secondes) sera appliquée.
ID du nom
nameID
est un champ facultatif utilisé pour définir les propriétés de l’élément NameID
dans une réponse SAML.
Format
format
est un champ facultatif utilisé pour définir le format NameID qui sera utilisé
dans l’assertion SAML. Lorsqu’elle n’est pas définie, une valeur de
'urn:oasis:names:tc:SAML:1.0:nameid-format:unspecified'
sera appliquée. Si une
règle NameIDPolicy est définie dans la requête d’authentification SAML, elle doit correspondre au
format NameID défini sur le client. Pour plus de détails sur le format NameID, veuillez consulter
les sections 2.2, 3.4.1 et 8.3 du document SAML spec.
Mappage des attributs
attrMapping
définit la valeur NameID
dans la réponse SAML. Si la valeur n’est pas définie, c’est le sujet de l’utilisateur
qui sera utilisé. Pour charger un attribut du cache de session, utilisez
la syntaxe connectorName.attributeValue
.
Requête de vérification
requestVerification
définit la clé publique utilisée pour valider la signature des
requêtes entrantes. Il est également possible de l’utiliser pour désactiver la vérification de la signature des requêtes.
Certificat
certificate
correspond au certificat RSA x509, qui sera utilisé pour vérifier les signatures des requêtes entrantes. Cette valeur peut être définie en ligne ou à l’aide d’un fournisseur de secrets. Elle doit être compatible avec le système RSA. Actuellement, ce fournisseur d’authentification ne prend en charge que l’algorithme SHA-256 pour la signature et le prétraitement des requêtes.
Ignorer la vérification
skipVerification
est une valeur booléenne utilisée lorsque le client ne souhaite pas valider les signatures des requêtes entrantes.
Authentification
authentication
définit la manière dont les utilisateurs sont authentifiés pour cette application.
IDPs
idps
répertorie les fournisseurs d’identité utilisés pour authentifier l’utilisateur.
Extension de services IsAuthenticated
isAuthenticatedSE
est une extension de services optionnelle qui peut être utilisée pour modifier le
comportement par défaut qui détermine si un utilisateur est déjà authentifié. Cette extension
doit être utilisée avec authenticateSE
.
Extension de services Authenticate
authenticateSE
est une extension de services optionnelle utilisée pour contrôler la manière dont
l’authentification est effectuée. Cette extension doit être utilisée avec isAuthenticatedSE
.
Authorization
authorization
est une configuration optionnelle qui définit les règles de contrôle d’accès qui
sont nécessaires pour accéder à l’application.
authorization
est omise, la valeur par défaut est
allowAll: true
. Tous les utilisateurs authentifiés seront autorisés à accéder à l’application.Allow All
allowAll
permet un accès libre à une application donnée. Cette option est généralement utilisée lorsque
l’autorisation à granularité fine n’est pas appliquée.
Règles
rules
définit une liste de conditions de contrôle d’accès. Toutes les règles doivent être évaluées avec une valeur « true »
pour permettre à l’utilisateur d’accéder à une application donnée.
Extension de services IsAuthorized
isAuthorizedSE
est une extension de services optionnelle qui peut être utilisée pour remplacer le
comportement par défaut qui détermine si un utilisateur est autorisé.
And
and
définit une liste de conditions qui doivent toutes être remplies.
Or
or
définit une liste de conditions dont au moins une doit être remplie.
Opérateurs
Les opérateurs définis ci-dessous peuvent être répertoriés sous une règle or
ou and
. Tous les opérateurs
attendent exactement deux valeurs (opérandes).
Pour charger un attribut du cache de session qui sera exploité dans la politque,
utilisez la syntaxe {{ connectorName.attributeName }}
. Par exemple, {{ ldap.memberOf }}
pourrait être utilisé pour rédiger une politique basée sur l’appartenance à un groupe LDAP.
En outre, une méthode de requête HTTP peut être prise en compte lors de l’évaluation de la politique en
utilisant la syntaxe {{ http.request.method }}
. La méthode de requête HTTP sera
renvoyée sous la forme d’une chaîne en majuscules, par exemple, POST
. Veuillez noter que seul l’attribut de méthode de requête HTTP
peut être utilisé dans la politique, la prise en charge d’autres attributs HTTP
sera introduite progressivement.
equals
s’évalue avec une valeur « true » si les deux valeurs sont équivalentes.
notEquals
s’évalue avec une valeur « true » si les deux valeurs ne sont pas équivalentes.
contains
s’évalue avec une valeur « true » si l’opérande de gauche (la chaîne complète) contient
l’opérande de droite (une sous-chaîne).
notContains
s’évalue avec une valeur « true » si l’opérande de gauche (la chaîne complète)
ne contient pas l’opérande de droite (une sous-chaîne).
Attribute Providers
attrProviders
constituent une configuration facultative pour un système d’identité ou
un magasin de données à partir duquel le SAMLProvider peut récupérer des attributs supplémentaires utilisés
dans claimsMapping
.
Connecteur
Connector est une référence au nom du connecteur défini qui sera utilisé en tant que fournisseur d’attributs.
usernameMapping
La configuration usernameMapping
permet de s’assurer que le fournisseur d’attributs (c’est-à-dire le connecteur LDAP) dispose de l’attribut correct nécessaire à l’interrogation des attributs de l’utilisateur.
Elle spécifie l’attribut utilisé pour rechercher les attributs utilisateur à partir du fournisseur d’attributs défini.
Chiffrement
encryption
est une configuration facultative utilisée pour crypter l’assertion SAML.
Méthode de chiffrement de clé
keyEncryptMethod
permet de configurer la méthode de chiffrement de la clé symétrique
utilisée pour chiffrer l’assertion. Deux valeurs sont actuellement prises en charge :
RSA_OAEP
et RSA-1_5.
Conformément aux spécifications de cryptage XML,
la valeur RSA-1_5
n’est pas recommandée en raison
des risques de sécurité associés à l’algorithme.
Méthode de chiffrement des données
dataEncryptMethod
permet de configurer la méthode de chiffrement des données réelles
de l’assertion. Les valeurs valides sont AES128CBC
, AES192CBC
et AES256CBC
.
Digest Method
digestMethod
correspond à l’algorithme de prétraitement des messages utilisé pour le calcul dudit prétraitement
dans le cadre du processus de cryptage. Les valeurs valides sont SHA256
et SHA512
.
Certificat
certificate
correspond à la chaîne encodée au format PEM qui peut être définie en ligne ou par l’intermédiaire d’un
fournisseur de secrets. Ce certificat est généralement récupéré auprès du fournisseur de services.
Mappage des réclamations
claimsMapping
définit comment mapper les attributs de la session à une assertion SAML.
Extension de services Build Claims
buildClaimsSE
est une extension de services optionnelle qui permet de personnaliser les attributs
qui seront ajoutés à l’élément AttributeStatement de SAML 2.0.
bool
, int
, int8
, int32
, int64
, float32
, float64
et string
.Exemples
Exemple de configuration de base de l’application SAML
apps:
- name: exampleSAMLApp
type: saml
audience: https://app.enterprise.com
consumerServiceURL: https://app.enterprise.com/acs
logoutServiceURL: https://app.enterprise.com/logout
idpInitiatedLogin:
loginURL: https://idp.enterprise.com/sso/example-app
relayStateURL: https://app.enterprise.com/index.html
duration: 300
requestVerification:
certificate: <appSigningCertificate>
nameID:
format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
attrMapping: azure.email
authentication:
idps:
- azure
attrProviders:
- connector: ldap
usernameMapping: azure.email
encryption:
keyEncryptMethod: RSA_OAEP
dataEncryptMethod: AES256CBC
digestMethod: SHA256
certificate: <encryptionCert>
claimsMapping:
id: azure.name
email: azure.email
lastName: azure.surname
groups: ldap.groupMembership
Exemple de configuration de l’application SAML avec règles d’autorisation
apps:
- name: exampleSAMLApp
type: saml
audience: https://app.enterprise.com
consumerServiceURL: https://app.enterprise.com/acs
requestVerification:
certificate: <appSigningCertificate>
authentication:
idps:
- azure
attrProviders:
- connector: ldap
usernameMapping: azure.email
authorization:
rules:
- and:
- contains: [ "{{ ldap.groups }}", "admin" ]
- contains: ["{{ azure.emailaddress }}", "@example.com"]
Application SAML avec extensions de services
apps:
- name: exampleSAMLApp
type: saml
audience: https://app.enterprise.com
consumerServiceURL: https://app.enterprise.com/acs
duration: 300
requestVerification:
certificate: <appSigningCertificate>
idpInitiatedLogin:
loginURL: https://idp.enterprise.com/sso/example-app
buildRelayStateSE:
funcName: BuildRelayState
file: /etc/maverics/extensions/auth.go
authentication:
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/auth.go
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/auth.go
authorization:
isAuthorizedSE:
funcName: IsAuthorized
file: /etc/maverics/auth.go
attrProviders:
- connector: ldap
usernameMapping: azure.email
buildClaimsSE:
funcName: BuildClaims
file: /etc/maverics/extensions/auth.go
/etc/maverics/extensions/auth.go
package main
import (
"fmt"
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func IsAuthenticated(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) bool {
logger := api.Logger()
logger.Debug("se", "determining if user is authenticated")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
isAzureAuth, err := session.GetString("azure.authenticated")
if err != nil {
logger.Error("se", "unable to retrieve attribute 'azure.authenticated'", "error", err)
return false
}
if isAzureAuth == "true" {
return true
}
return false
}
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
logger := api.Logger()
logger.Info("se", "authenticating user")
azureIDP, err := api.IdentityProvider("azure")
if err != nil {
logger.Error(
"se", "failed to retrieve Azure IDP",
"error", err.Error(),
)
http.Error(
rw,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError,
)
return
}
azureIDP.Login(rw, req)
}
func IsAuthorized(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) bool {
logger := api.Logger()
logger.Debug("se", "determining if user is authorized")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
rawGroups, _ := session.GetString("azure.groups")
groups := strings.Split(rawGroups, ",")
for _, group := range groups {
if group == "executives" {
return true
}
}
return false
}
func BuildClaims(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) (map[string]any, error) {
logger := api.Logger()
logger.Info("se", "building custom claims")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return nil, err
}
name, _ := session.GetString("azure.email")
firstName, _ := session.GetString("azure.givenname")
lastName, _ := session.GetString("azure.surname")
return map[string]any{
"name": name,
"firstName": firstName,
"lastName": lastName,
}, nil
}
func BuildRelayState(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) string {
const fallbackRelayState = "https://app.enterprise.com/index.html"
logger := api.Logger()
logger.Info("se", "building custom relay state")
session, err := api.Session()
if err != nil {
logger.Error(
"se", "failed to build RelayState: failed to retrieve session",
"error", err.Error(),
)
return fallbackRelayState
}
userID, err := session.GetString("azure.objectidentifier")
if err != nil {
logger.Error(
"se", "failed to build RelayState: failed to retrieve value from session",
"error", err.Error(),
)
return fallbackRelayState
}
if userID == "" {
logger.Error(
"se", "failed to build RelayState: user ID value not found session",
)
return fallbackRelayState
}
return fmt.Sprintf("https://app.enterprise.com/user/%s", userID)
}