SAML-Token mittels eines JAAS-Anmeldemoduls in einem Stack generieren und konsumieren

Sie können die APIs des Typs "GenericSecurityTokenFactory" verwenden, um ein SAML-Token, das Sie erstellt haben, an das Modul "SAMLGenerateLoginModule" oder das Modul "GenericIssuedTokenGenerateLoginModule" zu übergeben. Außerdem können Sie mit diesen APIs SAML-Token abrufen, die vom Modul "SAMLConsumeLoginModule" oder "GenericIssuedTokenConsumeLoginModule" konsumiert werden.

Vorbereitende Schritte

Es wird vorausgesetzt, dass ein funktionierender Satz von JAX-WS-Service-Client- und - Provider-Anwendungen vorhanden ist, dem Sie neue JAAS-Anmeldemodulklassen hinzufügen können.

Informationen zu diesem Vorgang

Mit dieser Task wird ein SAML 1.1-Bearer-Token (Trägertoken) generiert. Dieses kann jedoch ohne großen Aufwand modifiziert werden, um Sender-Vouches und die SAML-Version, die von der Laufzeitumgebung unterstützt wird, zu verwenden.

Obwohl Sie ein Anmeldemodul im Stack unterhalb von "SAMLGenerateLoginModule" anordnen können, um ein von dieser Klasse erstelltes SAML-Token zu überprüfen, ist es nicht möglich, ein auf diese Art und Weise gewonnenes SAML-Token zu modifizieren, es sei denn, das Token enthält keine digitale Signatur. Wenn Sie ein SAML-Token modifizieren, das eine digitale Signatur enthält, wird die XML für das SAML-Token entsprechend Ihren Aktualisierungen angepasst. Weil das Token jedoch signiert wurde, bevor Sie es aktualisiert haben, schlägt die Signaturvalidierung beim Empfänger fehl.

Mit dieser Task wird ein SAML 1.1-Bearer-Token (Trägertoken) generiert. Sie können jedoch jede SAML-Version und jeden Typ verwenden, die von der Laufzeitumgebung unterstützt werden. Weitere Informationen zum Erstellen und Modifizieren von SAML-Token mit den APIs des Typs "GenericSecurityTokenFactory" finden Sie im Artikel SAML-Anwendungen entwickeln. Weitere Informationen darüber, wie Sie das Token in den Clientanforderungskontext aufnehmen anstatt ein JAAS-Anmeldemodul zu verwenden, finden Sie in der Beschreibung der Konstanten "com.ibm.wsspi.wssecurity.token.tokenHolder" und "com.ibm.wsspi.wssecurity.token.enableCaptureTokenContext" in der Dokumentation zu "com.ibm.wsspi.wssecurity.core.Constants".

Weil das Generatorbeispiel nicht einfach für die Verwendung eines HoK (Holder-of-Key) geändert werden kann, wird am Ende dieser Task ein Beispiel der Methode "createSamlToken()" aufgeführt, das spezifisch für SAML-Holder-of-Key ist.

Vorgehensweise

  1. Erstellen Sie das folgende Generator-JAAS-Anmeldemodul und machen Sie es für Ihren Anwendungscode verfügbar.
    package test.tokens;
    
    import java.util.ArrayList;
    import java.util.Map;
    import javax.security.auth.Subject;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.login.LoginException;
    import javax.security.auth.spi.LoginModule;
    import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
    import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
    import com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory;
    import com.ibm.wsspi.wssecurity.saml.config.CredentialConfig;
    import com.ibm.wsspi.wssecurity.saml.config.ProviderConfig;
    import com.ibm.wsspi.wssecurity.saml.config.RequesterConfig;
    import com.ibm.wsspi.wssecurity.saml.data.SAMLAttribute;
    import com.ibm.wsspi.wssecurity.core.config.KeyInformationConfig;
    import com.ibm.wsspi.wssecurity.core.config.KeyStoreConfig;
    import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
    
    public class MySamlGenerator implements LoginModule {
    
      private Map _sharedState;
      private Map _options;
      private CallbackHandler _handler;
    
      public void initialize(Subject subject, CallbackHandler callbackHandler,
                             Map<String, ?> sharedState, Map<String, ?> options) {
    
        this._handler = callbackHandler;
        this._sharedState = sharedState;
        this._options = options;  
      }
      public boolean login() throws LoginException {
    
        GenericSecurityTokenFactory factory = null;
        try  {    
          factory = GenericSecurityTokenFactory.getInstance();
        } catch (Exception e)  {
          throw new LoginException(e.toString());
        }
        if (factory == null) {
          throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
        }
        SAMLToken myToken = null;
        try  {    
          myToken = createSamlToken();
        } catch (Exception e)  {
          throw new LoginException(e.toString());
        }
        if (myToken == null) {
          throw new LoginException("myToken is null");
        }
    
        //Nehmen Sie das Token in eine Liste für den gemeinsamen Status (Shared State) auf, wo es
        //für andere Anmeldemodule im Stack verfügbar ist
        factory.putGeneratorTokenToSharedState(_sharedState, myToken);
    
        return true;
      }
    
      private SAMLToken createSamlToken() throws Exception {
        //SAML-Bearer-Beispiel
        SAMLTokenFactory samlFactory = SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV11Token11);
        RequesterConfig reqData = samlFactory.newBearerTokenGenerateConfig();
        reqData.setAuthenticationMethod("Password"); //Authentication method for Assertion
    
        ProviderConfig samlIssuerCfg = samlFactory.newDefaultProviderConfig("self-issue");
    
        CredentialConfig cred = samlFactory.newCredentialConfig ();
        cred.setRequesterNameID("Alice");   // SAML NameIdentifier
    	  
        //Einige SAML-Attribute hinzufügen:
        SAMLAttribute attribute = new SAMLAttribute
          ("email", new String[] {"joe@websphere"},null, "WebSphere", "email", "joe");
        ArrayList<SAMLAttribute> al = new ArrayList<SAMLAttribute>();
        al.add(attribute);
        attribute = new SAMLAttribute("Membership", 
          new String[] {"Super users", "My team"}, null, null, null, null  );
        al.add(attribute);
        cred.setSAMLAttributes(al);
    
        SAMLToken samlToken = samlFactory.newSAMLToken(cred, reqData, samlIssuerCfg);
    
        return samlToken;
      }
    
      public boolean logout() throws LoginException {
        return false;
      } 
      public boolean abort() throws LoginException {
        return false;
      }
      public boolean commit() throws LoginException {
        return true;
      }
    }
  2. Erstellen Sie das folgende Konsumenten-JAAS-Anmeldemodul und machen Sie es für Ihren Anwendungscode verfügbar.
    package test.tokens;
    
    import java.util.Map;
    import javax.security.auth.Subject;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.login.LoginException;
    import javax.security.auth.spi.LoginModule;
    import javax.xml.namespace.QName;
    import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
    import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
    import com.ibm.websphere.wssecurity.wssapi.token.SAMLTokenFactory;
    import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
    
    public class MySamlConsumer implements LoginModule {
    
      private Map _sharedState;
      private Map _options;
      private CallbackHandler _handler;
    
      public void initialize(Subject subject, CallbackHandler callbackHandler,
                             Map<String, ?> sharedState, Map<String, ?> options) {
    
        this._handler = callbackHandler;
        this._sharedState = sharedState;
        this._options = options;  
      }
      public boolean login() throws LoginException {
    
        GenericSecurityTokenFactory factory = null;
        try  {    
          factory = GenericSecurityTokenFactory.getInstance();
        } catch (Exception e)  {
          throw new LoginException(e.toString());
        }
        if (factory == null) {
          throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
        }
        //Das von "GenericIssuedConsumeLoginModule" konsumierte Token abrufen
        SecurityToken myToken = factory.getConsumerTokenFromSharedState(_sharedState, new QName(SAMLTokenFactory.WssSamlV11Token11));
        if (myToken == null) {
            throw new LoginException("myToken is null");
        }
        if (myToken instanceof SAMLToken) {
        	//SAML-Token mit SAML-APIs untersuchen
        	SAMLToken samlToken = (SAMLToken)myToken;
        	String id = samlToken.getSamlID();
        	String subjectDns = samlToken.getSubjectDNS();
        	//...    	
        } else {
        	throw new LoginException("Did not receive a SAML token");
        }
        return true;
      }
      public boolean logout() throws LoginException {
        return false;
      } 
      public boolean abort() throws LoginException {
        return false;
      }
      public boolean commit() throws LoginException {
        return true;
      }
    }
  3. Erstellen Sie eine JAAS-Anmeldekonfiguration.
    1. Wählen Sie in der Administrationskonsole Sicherheit > Globale Sicherheit aus.
    2. Klicken Sie unter "Authentifizierung" auf Java Authentication and Authorization Service > Systemanmeldungen.
    3. Erstellen Sie den SAML-Tokengenerator.
      1. Klicken Sie auf Neu, und geben Sie unter "Alias" test.generate.saml ein.
      2. Klicken Sie unter "JAAS-Anmeldemodule" auf Neu und geben Sie unter "Name der Modulklasse" den Namen test.tokens.MySamlGenerator ein. Wählen Sie Proxy für Anmeldemodul verwenden aus und klicken Sie auf OK.
      3. Klicken Sie auf Neu, und geben Sie unter "Name der Modulklasse" den Namen com.ibm.ws.wssecurity.wssapi.token.impl.SAMLGenerateLoginModule ein. Klicken Sie auf OK.
    4. Erstellen Sie den SAML-Tokenkonsumenten.
      1. Klicken Sie im Navigationspfad auf JAAS - Systemanmeldungen, um zur Seite "JAAS-Systemanmeldungen" zurückzukehren.
      2. Klicken Sie auf Neu, und geben Sie unter "Alias" test.consume.saml ein.
      3. Klicken Sie unter "JAAS-Anmeldemodule" auf Neu und geben Sie unter "Name der Modulklasse" den Namen com.ibm.ws.wssecurity.wssapi.token.impl.SAMLConsumeLoginModule ein. Wählen Sie Proxy für Anmeldemodul verwenden aus und klicken Sie auf OK.
      4. Klicken Sie auf Speichern.
  4. Konfigurieren Sie den SAML-Tokengenerator für die Verwendung der neuen JAAS-Anmeldekonfiguration.
    1. Öffnen Sie in der Administrationskonsole die Bindungskonfiguration, die geändert werden soll.
    2. Wählen Sie WS-Security > Authentifizierung und Zugriffsschutz aus.
    3. Wählen Sie unter "Authentifizierungstoken" das abgehende SAML-Token aus, das Sie ändern möchten.
    4. Wählen Sie unter "JAAS-Anmeldung" test.generate.saml aus.
  5. Konfigurieren Sie den SAML-Tokenkonsumenten für die Verwendung der neuen JAAS-Anmeldekonfiguration.
    1. Öffnen Sie in der Administrationskonsole die Bindungskonfiguration, die geändert werden soll.
    2. Wählen Sie WS-Security > Authentifizierung und Zugriffsschutz aus.
    3. Wählen Sie unter "Authentifizierungstoken" das eingehende SAML-Token aus, das Sie ändern möchten.
    4. Wählen Sie unter "JAAS-Anmeldung" test.consume.saml aus.
  6. Klicken Sie auf Speichern.
  7. Starten Sie den Anwendungsserver erneut, um die JAAS-Konfigurationsänderungen anzuwenden.
  8. Testen Sie den Service.

Beispiel

Das folgende Beispiel veranschaulicht die Methode "createSamlToken()", mit der ein asymmetrisches SAML 2.0-HoK-Token (Holder-of-Key) erstellt wird.
private SAMLToken createSamlToken() throws Exception {
  SAMLTokenFactory samlFactory = SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV20Token11);

  RequesterConfig reqData = samlFactory.newAsymmetricHolderOfKeyTokenGenerateConfig();
  reqData.setAuthenticationMethod("Password");  //Authentifizierungsmethode für die Zusicherung

  ProviderConfig samlIssuerCfg = samlFactory.newDefaultProviderConfig("self-issue");

  CredentialConfig cred = samlFactory.newCredentialConfig ();
  cred.setRequesterNameID("Alice");   // SAML-Namens-ID

  // (Optional) Wenn Sie Keystore- und Schlüsseleigenschaften festlegen möchten,
  // die von den Eigenschaften in der Datei "SAMLIssuerConfig.properties" abweichen,
  // müssen Sie die Keystore-, Truststore- und Aliasinformationen im Objekt
  // ProviderConfig zurücksetzen.
  KeyInformationConfig kic = samlFactory.newKeyInformationConfig("private_key","keypass","CN=Private");

  KeyStoreConfig ksc = samlFactory.newKeyStoreConfig("jks","/keystores/myKeystore.ks","storepass");

  samlIssuerCfg.setKeyStoreConfig(ksc);    //Keystore mit dem privaten Schlüssel
  samlIssuerCfg.setTrustStoreConfig(ksc);  //Keystore mit dem öffentlichen Schlüssel

  // Legen Sie den Alias für das öffentliche Zertifikat fest, das im Truststore vorhanden sein muss.
  // Für diesen Alias darf kein Kennwort erforderlich sein.
  reqData.setKeyAliasForRequester("public_cert");  

  SecurityToken samlToken = samlFactory.newSAMLToken(cred, reqData, samlIssuerCfg);     

  // Privaten Schlüssel aus dem Keystore abrufen
  WSSUtilFactory wssufactory = WSSUtilFactory.getInstance();
  java.security.KeyStore ks = wssufactory.getKeyStore("jks","/keystores/myKeystore.ks",
                                                      "storepass".toCharArray());
  java.security.Key privateKey = ks.getKey("private_key", "keypass".toCharArray());

  // Den privaten Schlüssel dem Token hinzufügen, damit das Token verwendet werden kann,
  // um Elemente in einer SOAP-Nachricht zu signieren. ((com.ibm.ws.wssecurity.wssapi.token.impl.SecurityTokenImpl)samlToken).
  setKey(SecurityToken.SIGNING_KEY, privateKey);  ((com.ibm.ws.wssecurity.wssapi.token.impl.SecurityTokenImpl)samlToken).
  setKey(SecurityToken.DECRYPTING_KEY, privateKey);

  return samlToken;
}

Symbol, das den Typ des Artikels anzeigt. Taskartikel



Symbol für Zeitmarke Letzte Aktualisierung: 25.05.2016
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=twbs_gen_con_token_JAAS_mod
Dateiname:twbs_gen_con_token_JAAS_mod.html