GenericSecurityTokenFactory API를 사용하여
작성한 SAML 토큰을 SAMLGenerateLoginModule
또는 GenericIssuedTokenGenerateLoginModule 모듈에 전달할 수 있습니다. 또한 이러한 API를 사용하여
SAMLConsumeLoginModule 또는 GenericIssuedTokenConsumeLoginModule 모듈이 이용하는 SAML 토큰을 얻을 수 있습니다.
시작하기 전에
새 JAAS 로그인 모듈 클래스를 추가할 수 있는 JAX-WS 서비스 클라이언트와 제공자 애플리케이션의 작동하는 세트가 있어야 합니다.
이 태스크 정보
이 태스크는 SAML 1.1 전달자 토큰을 생성하지만 이 토큰은 전송자 인증 및 런타임 환경에서 지원되는 임의의 SAML 버전을 사용하기 위해
쉽게 수정할 수 있습니다.
해당 클래스에 의해 작성된 SAML 토큰을 검사하기 위해 로그인 모듈을
SAMLGenerateLoginModule 아래 스택할 수는 있지만 이러한 방식으로 얻은 SAML 토큰이 디지털 서명을 포함하는 경우 수정할 수 없습니다.
디지털 서명을 포함하는 SAML 토큰을 수정할 경우 이 SAML 토큰에 대한 XML은
업데이트 시 조정되지만 업데이트 전에 이 토큰에 서명했기 때문에 수신자에서
서명 유효성 검증에 실패합니다.
이 태스크는 SAML 1.1 전달자
토큰을 생성하지만 런타임 환경에서 지원되는 모든 SAML 버전 및 유형을 사용할 수 있습니다. GenericSecurityTokenFactory API를 사용한 SAML 토큰 작성 및 수정에 대한 자세한 정보는 SAML 애플리케이션 개발을 참조하십시오. JAAS 로그인 모듈을 사용하는 대신
토큰을 클라이언트의 요청 컨텍스트에 배치하는 방법에 대한 자세한 정보는
com.ibm.wsspi.wssecurity.core.Constants에서 com.ibm.wsspi.wssecurity.token.tokenHolder 및
com.ibm.wsspi.wssecurity.token.enableCaptureTokenContext 상수를 참조하십시오.
생성기 예는 HoK(holder-of-key)를 사용하도록 쉽게 수정할 수 없기 때문에 SAML HoK(holder-of-key)에 특정한 createSamlToken() 메소드의 예가 이 태스크 끝 부분에 제공됩니다.
프로시저
- 다음 생성기 JAAS 로그인 모듈을 작성하고 사용자의 애플리케이션 코드에 맞게 수정하여 사용하십시오.
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");
}
//Put the token in a list on the shared state where it will be available to be used by
//stacked login modules
factory.putGeneratorTokenToSharedState(_sharedState, myToken);
return true;
}
private SAMLToken createSamlToken() throws Exception {
//SAML Bearer example
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
//Add some SAML attributes:
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;
}
}
- 다음 이용자 JAAS 로그인 모듈을 작성하고 자신의 애플리케이션 코드에 맞게 수정하여 사용하십시오.
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");
}
//Get the token that was consumed by the GenericIssuedConsumeLoginModule
SecurityToken myToken = factory.getConsumerTokenFromSharedState(_sharedState, new QName(SAMLTokenFactory.WssSamlV11Token11));
if (myToken == null) {
throw new LoginException("myToken is null");
}
if (myToken instanceof SAMLToken) {
//Examine the SAML token with SAML APIs
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;
}
}
- JAAS 로그인 구성을 작성하십시오.
- 관리 콘솔에서 으로 이동하십시오.
- 인증 아래에서 으로 이동하십시오.
- SAML 토큰 생성기를 작성하십시오.
- 새로 작성을 클릭하고 별명에 test.generate.saml을 입력하십시오.
- JAAS 로그인 모듈에서 새로 작성을 클릭하고 모듈 클래스 이름에 test.tokens.MySamlGenerator를 입력하십시오.
로그인 모듈 프록시 사용을 선택하고 확인을 클릭하십시오.
- 새로 작성을 클릭하고 모듈 클래스 이름에 com.ibm.ws.wssecurity.wssapi.token.impl.SAMLGenerateLoginModule을 입력하십시오.
확인을 클릭하십시오.
- SAML 토큰 이용자를 작성하십시오.
- JAAS 시스템 로그인 페이지로 돌아가려면 이동 경로에서 JAAS - 시스템 로그인을 클릭하십시오.
- 새로 작성을 클릭하고 별명에 test.consume.saml을 입력하십시오.
- JAAS 로그인 모듈에서 새로 작성을 클릭하고 모듈 클래스 이름에 com.ibm.ws.wssecurity.wssapi.token.impl.SAMLConsumeLoginModule을 입력하십시오.
로그인 모듈 프록시 사용을 선택하고 확인을 클릭하십시오.
- 저장을 클릭하십시오.
- 새 JAAS 로그인 구성을 사용하도록 SAML 토큰 생성기를 구성하십시오.
- 관리 콘솔에서 변경하려는 바인딩 구성을 여십시오.
- 를 선택하십시오.
- 인증 토큰에서 변경할 SAML 아웃바운드 토큰을 선택하십시오.
- JAAS 로그인에서 test.generate.saml을 선택하십시오.
- 새 JAAS 로그인 구성을 사용하도록 SAML 토큰 이용자를 구성하십시오.
- 관리 콘솔에서 변경하려는 바인딩 구성을 여십시오.
- 를 선택하십시오.
- 인증 토큰에서 변경할 SAML 인바운드 토큰을 선택하십시오.
- JAAS 로그인에서 test.consume.saml을 선택하십시오.
- 저장을 클릭하십시오.
- 애플리케이션 서버를 다시 시작하여 JAAS 구성 변경사항을 적용하십시오.
- 서비스를 테스트하십시오.
예
다음 예에서는 createSamlToken() 메소드를 사용하여 비대칭 SAML 2.0 HoK(holder-of-key) 토큰을 작성하는 것을 보여줍니다.
private SAMLToken createSamlToken() throws Exception {
SAMLTokenFactory samlFactory = SAMLTokenFactory.getInstance(SAMLTokenFactory.WssSamlV20Token11);
RequesterConfig reqData = samlFactory.newAsymmetricHolderOfKeyTokenGenerateConfig();
reqData.setAuthenticationMethod("Password"); //Authentication method for Assertion
ProviderConfig samlIssuerCfg = samlFactory.newDefaultProviderConfig("self-issue");
CredentialConfig cred = samlFactory.newCredentialConfig ();
cred.setRequesterNameID("Alice"); // SAML NameIdentifier
// (Optional) If you want to use keystore and key properties other than what
// is set in the SAMLIssuerConfig.properties file, reset the keystore,
// trust store and alias information in the ProviderConfig object.
KeyInformationConfig kic = samlFactory.newKeyInformationConfig("private_key","keypass","CN=Private");
KeyStoreConfig ksc = samlFactory.newKeyStoreConfig("jks","/keystores/myKeystore.ks","storepass");
samlIssuerCfg.setKeyStoreConfig(ksc); //keystore that holds the private key
samlIssuerCfg.setTrustStoreConfig(ksc); //keystore that holds the public key
// Set the alias for the public certificate that must exist in the trust store.
// This alias must not require a password.
reqData.setKeyAliasForRequester("public_cert");
SecurityToken samlToken = samlFactory.newSAMLToken(cred, reqData, samlIssuerCfg);
// Get the private key from the key store
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());
// Add the private key to the token so that the token can be used to sign
// elements in a SOAP message. ((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;
}