Vous pouvez créer des jetons SAML auto-générés avec la méthode de confirmation du sujet bearer (porteur), puis
les envoyer dans des messages de demande de services Web à l'aide du modèle de programmation JAX-WS (Java™
API for XML-Based Web Services) et des API WSS (Web Services Security).
Avant de commencer
On considère ici que vous connaissez le modèle de programmation JAX-WS, les API WSS, les concepts de SAML et l'utilisation des ensembles de règles pour configurer et administrer les paramètres des services Web.
Pourquoi et quand exécuter cette tâche
Vous avez la possibilité de créer un client de services Web qui utilise les jetons SAML avec la méthode de confirmation du sujet bearer dans les messages de demande SOAP, en utilisant les interfaces de programmation de sécurité des services Web. L'emploi des interfaces de programmation dans un client de services Web pour définir l'utilisation de jetons SAML avec confirmation du sujet bearer constitue une solution alternative par rapport aux ensembles de règles et aux configurations de liaisons.
Il est possible de créer un jeton SAML auto-généré, puis de l'envoyer dans les messages de demande de services Web à partir d'un client de services Web. Le client d'application de services Web utilisé dans cette tâche est une version modifiée du code client contenu dans l'application modèle JaxWSServicesSamples disponible pour le téléchargement. Des fragments de code du modèle sont décrits dans la section Procédure, et la section Exemple contient un modèle de client de services Web prêt à l'emploi.
Procédure
- Identifiez et obtenez le client de services Web que vous souhaitez utiliser pour appeler un fournisseur de services Web.
Utilisez ce client pour programmer l'insertion des jetons SAML dans des messages de demande SOAP à l'aide des API WSS.
Le client de services Web utilisé dans cette procédure
est une version modifiée du code client contenu dans l'exemple d'application
de services Web JaxWSServicesSamples.
Pour obtenir le modèle de client de services Web et le modifier en ajoutant les API de Services de sécurité (WSS), afin de programmer la transmission de jetons SAML dans les messages de demande SOAP, procédez comme suit :
- Téléchargez l'exemple d'application JaxWSServicesSamples. Le modèle d'application JaxWSServicesSamples n'est pas installé par défaut.
- Obtenez le code client JaxWSServicesSamples.
Pour les besoins de l'exemple, cette procédure utilise une version modifiée du client léger Echo compris dans le modèle JaxWSServicesSamples. L'exemple de fichier client fin Echo de services Web, SampleClient.java,
est situé dans le répertoire src\SampleClientSei\src\com\ibm\was\wssample\sei\cli. L'exemple de fichier de classe est inclus au fichier WSSampleClientSei.jar.
L'application d'entreprise JaxWSServicesSamples.ear
et la prise en charge des fichiers d'archive Java
(JAR) sont situés dans le répertoire installableApps
dans l'exemple d'application JaxWSServicesSamples.
- Déployez le fichier JaxWSServicesSamples.ear
dans le serveur d'application. Une fois le fichier JaxWSServicesSamples.ear déployé, vous êtes prêt à tester le modèle de code de client de services Web avec le modèle d'application.
Au lieu d'utiliser le modèle de client de services web, vous pouvez choisir d'intégrer à votre propre
application client de services Web les fragments de code destinés à programmer la transmission des jetons SAML dans
les messages de demande SOAP à l'aide des API WSS. L'exemple pris dans cette procédure utilise un client léger de services Web JAX-WS ; il est cependant possible d'utiliser un client géré.
- Associez l'ensemble de règles par défaut SAML20 Bearer WSHTTPS au fournisseur de services Web. Cet ensemble de règles sert à protéger les messages à l'aide du transport HTTPS. Pour plus d'informations sur la façon d'associer l'ensemble de règles par défaut SAML20 Bearer WSHTTPS Default au fournisseur de services Web, reportez-vous à la section relative à la configuration des clients et des fournisseurs pour le jeton SAML bearer (porteur). L'exemple utilisé dans cette procédure utilise des jetons SAML auto-générés. Lorsque vous configurez les liaisons du fournisseur, faites coïncider la configuration du fichier de clés certifiées et le certificat avec la clé de signature du jeton auto-généré.
- Associez les liaisons générales par défaut du modèle SAML Bearer Provider Sample au modèle de fournisseur de services Web. Pour plus d'informations sur la façon d'affecter les liaisons générales par défaut du modèle par défaut SAML Bearer Provider Default à votre application de services Web, reportez-vous à la section relative à la configuration des clients et des fournisseurs pour le jeton SAML bearer (porteur).
- Créez le jeton SAML auto-généré. Le fragment de code ci-dessous illustre la création du jeton SAML :
// Create the SAML token.
HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
map.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
map.put(SamlConstants.SAML_NAME_IDENTIFIER, "Alice");
map.put(SamlConstants.SIGNATURE_REQUIRED, "true");
SAMLGenerateCallbackHandler callbackHandler = new SAMLGenerateCallbackHandler(map);
callbackHandler.setWSSGenerationContextForTrustClient(gencont);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml");
System.out.println("SAMLToken id = " + samlToken.getId());
- Utilisez la méthode CallService() pour spécifier les paramètres de configuration de sécurité de services Web requis pour appeler un fournisseur de services Web cible à l'aide d'un jeton SAML auto-généré.
La méthode
CallService() définit les paramètres de configuration requis
par l'environnement d'exécution de sécurité de services Web via la propriété personnalisée com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext pour générer un jeton SAMLToken auto-généré.
Pour plus d'informations sur la façon de définir des propriétés de configuration applicables au jeton, consultez la rubrique relative à la configuration d'un jeton SAML lors de sa création.
- Ajoutez le fichier JAR du client léger JAX-WS au chemin d'accès aux classes. Ajoutez le fichier racine_serveur_app/runtimes/com.ibm.jaxws.thinclient_8.5.0.jar
au chemin d'accès aux classes. Pour plus d'informations sur l'ajout de ce fichier JAR au chemin d'accès aux classes, consultez la rubrique relative au test des clients compatibles avec les services Web.
- Utilisez la méthode WSSFactory newSecurityToken pour définir la façon de créer le jeton SAML.
Indiquez la méthode suivante pour créer un jeton SAML :
WSSFactory newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml")
La création d'un jeton SAML requiert le droit d'accès Java wssapi.SAMLTokenFactory.newSAMLToken. Utilisez PolicyTool pour ajouter l'instruction de règle suivante au fichier de règles de sécurité Java ou au fichier du client d'application was.policy :
permission java.security.SecurityPermission "wssapi.SAMLTokenFactory.newSAMLToken
Le paramètre SAMLToken.class définit le type de jeton à créer.
L'objet
callbackHandler contient les paramètres qui définissent les caractéristiques du jeton SAML que vous créez. Cet objet pointe vers un objet SAMLGenerateCallbackHandler
qui définit les paramètres de configuration décrits dans le tableau ci-dessous :
Tableau 1. Propriétés de SAMLGenerateCallbackHandler. Ce tableau décrit les paramètres de configuration de l'objet SAMLGenerateCallbackHandler utilisant la méthode de confirmation du sujet bearer.Propriété |
Description |
Obligatoire |
SamlConstants.CONFIRMATION_METHOD |
Définit l'utilisation de la méthode de confirmation bearer. |
Oui |
SamlConstants.TOKEN_TYPE |
Utilise la valeur de la constante WSSConstants.SAML.SAML20_VALUE_TYPE, pour définir un type de jeton SAML 2.0.
Lorsqu'un client de services Web est associé à des ensembles de règles, cette propriété n'est pas utilisée par l'environnement d'exécution de sécurité des Services Web. Dans ce scénario, définissez le type de valeur du jeton à l'aide de l'attribut valueType de la configuration de liaison du générateur de jetons.
L'exemple pris dans cette procédure utilise un jeton SAML 2.0 ; il est cependant possible d'utiliser la valeur WSSConstants.SAML.SAML11_VALUE_TYPE.
|
Oui |
SamlConstants.SAML_NAME_IDENTIFIER |
Définit l'identité d'un utilisateur, par exemple monnom comme valeur de NameID dans le jeton SAML.
Si vous ne définissez pas ce paramètre lors de l'utilisation du client léger de services Web JAX-WS, la valeur de NameID ne contient aucune information utile.
Si vous utilisez un client géré de services web, par exemple une application Java Platform Enterprise Edition
(Java EE) effectuant un appel de demande de services web, l'environnement d'exécution de sécurité des services Web tente d'extraire les informations de sécurité relatives à l'utilisateur à partir du contexte de sécurité. De la même façon, si vous ne définissez pas ce paramètre pour un client géré de services Web, la valeur de NameID contient l'identificateur de nom UNAUTHENTICATED.
Cette propriété n'est pas utilisée si votre client de services Web est associé à des ensembles de règles. Consultez la rubrique relative à l'envoi de l'identité et des attributs du jeton SAML pour en savoir plus sur ce sujet.
|
Non |
SamlConstants.SIGNATURE_REQUIRED |
Définit si l'émetteur doit signer le jeton numériquement.
La valeur true indique que l'émetteur doit signer le jeton SAML de façon numérique.
Il s'agit de la valeur par défaut.
|
Non |
Le paramètre
system.wss.generate.saml définit le module de connexion JAAS (Java Authentication
and Authorization Service) utilisé pour créer le jeton SAML. Vous devez spécifier une propriété JVM pour définir un fichier de configuration JAAS contenant la configuration requise pour la connexion JAAS, par exemple :
-Djava.security.auth.login.config=profile_root/properties/wsjaas_client.conf
A la place, vous pouvez également spécifier un fichier de configuration de la connexion JAAS en définissant une propriété système Java dans le modèle de code client, par exemple :
System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf ");
- Obtenez l'identificateur du jeton SAML créé.
Utilisez l'instruction suivante comme une simple test pour le jeton SAML que vous avez créé :
System.out.println("SAMLToken id = " + samlToken.getId())
- Ajoutez le jeton SAML à l'en-tête de sécurité SOAP des messages de demande de services Web.
- Initialisez le client de services Web. Le fragment de code suivant illustre ces actions :
// Initialize web services client
EchoService12PortProxy echo = new EchoService12PortProxy();
echo._getDescriptor().setEndpoint(endpointURL);
// Configure SOAPAction properties
BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");
- Initialisez WSSGenerationContext. Le code ci-dessous illustre l'utilisation de l'interface WSSGenerationContext pour initialiser un contexte de génération et vous permettre d'insérer SAMLToken dans le message de demande de services Web :
// Initialize WSSGenerationContext
WSSGenerationContext gencont = factory.newWSSGenerationContext();
gencont.add(samlToken);
Spécifiquement, l'appel de la méthode
gencont.add(samlToken) définit l'insertion du jeton SAML dans un message de demande. Utilisez PolicyTool pour ajouter l'instruction de règle suivante au fichier de règles de sécurité Java ou au fichier du client d'application was.policy :
“permission javax.security.auth.AuthPermission "modifyPrivateCredentials"
- Ajoutez l'élément d'horodatage dans l'en-tête de sécurité des messages SOAP. L'ensemble de règles SAML20 Bearer WSHTTPS Default requiert que l'en-tête de sécurité SOAP des messages de demande de services Web et des messages de réponse contiennent un élément d'horodatage. Dans le fragment de code qui suit, la méthode factory.newWSSTimestamp() génère l'horodatage, et la méthode gencont.add(timestamp) spécifie l'heure et la date à insérer dans le message de demande :
// Add a timestamp to the request message.
WSSTimestamp timestamp = factory.newWSSTimestamp();
gencont.add(timestamp);
gencont.process(requestContext);
- Associez l'objet WSSGenerationContext à l'objet de services Web RequestContext. L'objet WSSGenerationContext contient désormais toutes les informations de sécurité nécessaires au formatage d'un message de demande. L'appel de méthode gencont.process(requestContext)associe l'objet WSSGenerationContext à l'objet RequestContext des services Web pour permettre à l'environnement d'exécution de sécurité des Services de mettre en forme l'en-tête de sécurité SOAP requis, par exemple :
// Attaches WSSGenerationContext object to the web services RequestContext object.
gencont.process(requestContext);
- Définissez la protection des messages de niveau transport SSL à l'aide des propriétés JVM.
L'ensemble de règles SAML20 Bearer WSHTTPS Default requiert la protection des messages au niveau du transport SSL. Définissez la protection des messages de niveau transport SSL à l'aide des propriétés JVM :
-Dcom.ibm.SSL.ConfigURL=file:racine_profil\properties\ssl.client.props
A la place, vous pouvez également définir le fichier de configuration SSL en définissant une propriété système Java dans le modèle de code client, par exemple :
System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");
Résultats
Vous avez créé un jeton SAML auto-généré avec la méthode de confirmation du sujet porteur puis
avez envoyé ce jeton avec des messages de demande de services Web à l'aide du modèle de programmation
JAX-WS et des API WSS.
Exemple
Le modèle de code qui suit est une application de client de services Web qui illustre la façon de créer un jeton SAML auto-généré, puis de l'envoyer
dans les messages de demande de services Web. Si votre scénario d'utilisation requiert des jetons SAML, mais ne nécessite pas que l'application les transmette par l'intermédiaire des messages de services Web, n'utilisez que la première partie du modèle de code, jusqu'à la section //
Initialiser le client de services Web.
/**
* The following source code is sample code created by IBM Corporation.
* This sample code is provided to you solely for the purpose of assisting you in the
* use of the technology. The code is provided 'AS IS', without warranty or condition of
* any kind. IBM shall not be liable for any damages arising out of your use of the
* sample code, even if IBM has been advised of the possibility of such damages.
*/
package com.ibm.was.wssample.sei.cli;
import com.ibm.was.wssample.sei.echo.EchoService12PortProxy;
import com.ibm.was.wssample.sei.echo.EchoStringInput;
import com.ibm.websphere.wssecurity.wssapi.WSSFactory;
import com.ibm.websphere.wssecurity.wssapi.WSSGenerationContext;
import com.ibm.websphere.wssecurity.wssapi.WSSConsumingContext;
import com.ibm.websphere.wssecurity.wssapi.WSSTimestamp;
import com.ibm.websphere.wssecurity.callbackhandler.SAMLGenerateCallbackHandler;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
import com.ibm.wsspi.wssecurity.core.token.config.WSSConstants;
import com.ibm.wsspi.wssecurity.saml.config.SamlConstants;
import java.util.Map;
import java.util.HashMap;
import javax.xml.ws.BindingProvider;
/**
* SampleClient
* main entry point for thin client JAR sample
* and worker class to communicate with the services
*/
public class SampleClient {
private String urlHost = "localhost";
private String urlPort = "9443";
private static final String CONTEXT_BASE = "/WSSampleSei/";
private static final String ECHO_CONTEXT12 = CONTEXT_BASE+"EchoService12";
private String message = "HELLO";
private String uriString = "https://" + urlHost + ":" + urlPort;
private String endpointURL = uriString + ECHO_CONTEXT12;
private String input = message;
/**
* main()
*
* see printusage() for command-line arguments
*
* @param args
*/
public static void main(String[] args) {
SampleClient sample = new SampleClient();
sample.CallService();
}
/**
* CallService Parms were already read. Now call the service proxy classes
*
*/
void CallService() {
String response = "ERROR!:";
try {
System.setProperty("java.security.auth.login.config", "profile_root/properties/wsjaas_client.conf ");
System.setProperty("com.ibm.SSL.ConfigURL", "file:profile_root/properties/ssl.client.props");
// Initialize WSSFactory object
WSSFactory factory = WSSFactory.getInstance();
// Initialize WSSGenerationContext
WSSGenerationContext gencont = factory.newWSSGenerationContext();
// Initialize SAML issuer configuration via custom properties
HashMap<Object, Object> customProps = new HashMap<Object,Object>();
customProps.put(SamlConstants.ISSUER_URI_PROP, "example.com");
customProps.put(SamlConstants.TTL_PROP, "3600000");
customProps.put(SamlConstants.KS_PATH_PROP, "keystores/saml-provider.jceks");
customProps.put(SamlConstants.KS_TYPE_PROP, "JCEKS");
customProps.put(SamlConstants.KS_PW_PROP, "{xor}LCswLTovPiws");
customProps.put(SamlConstants.KEY_ALIAS_PROP, "samlissuer");
customProps.put(SamlConstants.KEY_NAME_PROP, "CN=SAMLIssuer, O=EXAMPLE");
customProps.put(SamlConstants.KEY_PW_PROP, "{xor}NDomLz4sLA==");
customProps.put(SamlConstants.TS_PATH_PROP, "keystores/saml-provider.jceks");
customProps.put(SamlConstants.TS_TYPE_PROP, "JCEKS");
customProps.put(SamlConstants.TS_PW_PROP, "{xor}LCswLTovPiws");
gencont.add(customProps); //Add custom properties
// Create SAMLToken
HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(SamlConstants.CONFIRMATION_METHOD, "Bearer");
map.put(SamlConstants.TOKEN_TYPE, WSSConstants.SAML.SAML20_VALUE_TYPE);
map.put(SamlConstants.SAML_NAME_IDENTIFIER, "Alice");
map.put(SamlConstants.SIGNATURE_REQUIRED, "true");
SAMLGenerateCallbackHandler callbackHandler = new SAMLGenerateCallbackHandler(map);
SecurityToken samlToken = factory.newSecurityToken(SAMLToken.class, callbackHandler, "system.wss.generate.saml");
System.out.println("SAMLToken id = " + samlToken.getId());
// Initialize web services client
EchoService12PortProxy echo = new EchoService12PortProxy();
echo._getDescriptor().setEndpoint(endpointURL);
// Configure SOAPAction properties
BindingProvider bp = (BindingProvider) (echo._getDescriptor().getProxy());
Map<String, Object> requestContext = bp.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "echoOperation");
gencont.add(samlToken);
// Add timestamp
WSSTimestamp timestamp = factory.newWSSTimestamp();
gencont.add(timestamp);
gencont.process(requestContext);
// Build the input object
EchoStringInput echoParm =
new com.ibm.was.wssample.sei.echo.ObjectFactory().createEchoStringInput();
echoParm.setEchoInput(input);
System.out.println(">> CLIENT: SEI Echo to " + endpointURL);
// Prepare to consume timestamp in response message.
WSSConsumingContext concont = factory.newWSSConsumingContext();
concont.add(WSSConsumingContext.TIMESTAMP);
concont.process(requestContext);
// Call the service
response = echo.echoOperation(echoParm).getEchoResponse();
System.out.println(">> CLIENT: SEI Echo invocation complete.");
System.out.println(">> CLIENT: SEI Echo response is: " + response);
} catch (Exception e) {
System.out.println(">> CLIENT: ERROR: SEI Echo EXCEPTION.");
e.printStackTrace();
}
}
}
Lorsque ce modèle d'application client de services Web fonctionne correctement, vous recevez des messages du type :
SAMLToken id = _191EBC44865015D9AB1270745072344
Retrieving document at 'file:profile_root/.../wsdl/'.
>> CLIENT: SEI Echo to https://localhost:9443/WSSampleSei/EchoService12
>> CLIENT: SEI Echo invocation complete.
>> CLIENT: SEI Echo response is: SOAP12==>>HELLO