blob: b4800f008ee391306ebe5fe6ca02c64ea28f0be5 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.swssf.wss.impl.securityToken;
import org.apache.commons.codec.binary.Base64;
import org.swssf.binding.wss10.BinarySecurityTokenType;
import org.swssf.binding.wss10.KeyIdentifierType;
import org.swssf.binding.wss10.SecurityTokenReferenceType;
import org.apache.xml.security.binding.xmldsig.*;
import org.apache.xml.security.binding.xmldsig11.ECKeyValueType;
import org.swssf.wss.ext.*;
import org.swssf.wss.crypto.Crypto;
import org.apache.xml.security.stax.ext.*;
import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
import org.apache.xml.security.stax.impl.securityToken.DsaKeyValueSecurityToken;
import org.apache.xml.security.stax.impl.securityToken.ECKeyValueSecurityToken;
import org.apache.xml.security.stax.impl.securityToken.RsaKeyValueSecurityToken;
import org.apache.xml.security.stax.impl.securityToken.SecurityTokenFactory;
import javax.security.auth.callback.CallbackHandler;
import java.util.Deque;
/**
* Factory to create SecurityToken Objects from keys in XML
*
* @author $Author$
* @version $Revision$ $Date$
*/
public class SecurityTokenFactoryImpl extends SecurityTokenFactory {
public SecurityTokenFactoryImpl() {
}
public SecurityToken getSecurityToken(KeyInfoType keyInfoType, SecurityToken.KeyInfoUsage keyInfoUsage,
XMLSecurityProperties securityProperties, SecurityContext securityContext) throws XMLSecurityException {
Crypto crypto = null;
if (keyInfoUsage == SecurityToken.KeyInfoUsage.SIGNATURE_VERIFICATION) {
crypto = ((WSSSecurityProperties)securityProperties).getSignatureVerificationCrypto();
} else if (keyInfoUsage == SecurityToken.KeyInfoUsage.DECRYPTION) {
crypto = ((WSSSecurityProperties)securityProperties).getDecryptionCrypto();
}
if (keyInfoType != null) {
final SecurityTokenReferenceType securityTokenReferenceType
= XMLSecurityUtils.getQNameType(keyInfoType.getContent(), WSSConstants.TAG_wsse_SecurityTokenReference);
if (securityTokenReferenceType != null) {
return getSecurityToken(securityTokenReferenceType, crypto, securityProperties.getCallbackHandler(), securityContext);
}
final KeyValueType keyValueType
= XMLSecurityUtils.getQNameType(keyInfoType.getContent(), WSSConstants.TAG_dsig_KeyValue);
if (keyValueType != null) {
return getSecurityToken(keyValueType, crypto, securityProperties.getCallbackHandler(), securityContext);
}
} else if (crypto.getDefaultX509Identifier() != null) {
return new X509DefaultSecurityToken(
(WSSecurityContext) securityContext, crypto, securityProperties.getCallbackHandler(), crypto.getDefaultX509Identifier(),
crypto.getDefaultX509Identifier(), null
);
}
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noKeyinfo");
}
public static SecurityToken getSecurityToken(SecurityTokenReferenceType securityTokenReferenceType, Crypto crypto,
final CallbackHandler callbackHandler, SecurityContext securityContext)
throws XMLSecurityException {
//BSP.R5205 is a joke. In real life we have a lot of cases which prevents a one pass processing.
//Say encrypted Tokens, SignedTokens, Signed-Timestamp first...
try {
if (securityTokenReferenceType == null) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noSecTokRef");
}
if (securityTokenReferenceType.getAny().size() > 1) {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3061);
}
//todo BSP.R3027 KeyName? not supported ATM
//todo BSP.R3060,BSP.R3025,BSP.R3056 only one Embedded element? Not supported ATM
final X509DataType x509DataType
= XMLSecurityUtils.getQNameType(securityTokenReferenceType.getAny(), WSSConstants.TAG_dsig_X509Data);
if (x509DataType != null) {
return new X509DataSecurityToken((WSSecurityContext) securityContext, crypto, callbackHandler,
x509DataType, securityTokenReferenceType.getId(),
WSSConstants.WSSKeyIdentifierType.ISSUER_SERIAL);
}
final KeyIdentifierType keyIdentifierType
= XMLSecurityUtils.getQNameType(securityTokenReferenceType.getAny(), WSSConstants.TAG_wsse_KeyIdentifier);
if (keyIdentifierType != null) {
String valueType = keyIdentifierType.getValueType();
if (valueType == null) {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3054);
}
String encodingType = keyIdentifierType.getEncodingType();
byte[] binaryContent = null;
if (WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING.equals(encodingType)) {
binaryContent = Base64.decodeBase64(keyIdentifierType.getValue());
} else if (!WSSConstants.NS_SAML10_TYPE.equals(valueType) && !WSSConstants.NS_SAML20_TYPE.equals(valueType)) {
if (encodingType == null) {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3070);
} else {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3071);
}
}
if (WSSConstants.NS_X509_V3_TYPE.equals(valueType)) {
return new X509_V3SecurityToken(
(WSSecurityContext) securityContext, crypto, callbackHandler,
binaryContent, securityTokenReferenceType.getId(), WSSConstants.WSSKeyIdentifierType.X509_KEY_IDENTIFIER);
} else if (WSSConstants.NS_X509SubjectKeyIdentifier.equals(valueType)) {
return new X509SubjectKeyIdentifierSecurityToken(
(WSSecurityContext) securityContext, crypto, callbackHandler, binaryContent,
securityTokenReferenceType.getId(), WSSConstants.WSSKeyIdentifierType.SKI_KEY_IDENTIFIER);
} else if (WSSConstants.NS_THUMBPRINT.equals(valueType)) {
return new ThumbprintSHA1SecurityToken(
(WSSecurityContext) securityContext, crypto, callbackHandler, binaryContent,
securityTokenReferenceType.getId(), WSSConstants.WSSKeyIdentifierType.THUMBPRINT_IDENTIFIER);
} else if (WSSConstants.NS_SAML10_TYPE.equals(valueType) || WSSConstants.NS_SAML20_TYPE.equals(valueType)) {
SecurityTokenProvider securityTokenProvider = securityContext.getSecurityTokenProvider(keyIdentifierType.getValue());
if (securityTokenProvider == null) {
throw new WSSecurityException(
WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "noToken", keyIdentifierType.getValue());
}
return securityTokenProvider.getSecurityToken();
} else {
//we do enforce BSP compliance here but will fail anyway since we cannot identify the referenced token
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3063);
}
}
final org.swssf.binding.wss10.ReferenceType referenceType
= XMLSecurityUtils.getQNameType(securityTokenReferenceType.getAny(), WSSConstants.TAG_wsse_Reference);
if (referenceType != null) {
//We do not check for BSP.R3023, BSP.R3022, BSP.R3066, BSP.R3067, BSP.R3024, BSP.R3064, BSP.R3211, BSP.R3058, BSP.R3059
String uri = referenceType.getURI();
if (uri == null) {
//we do enforce BSP compliance here but will fail anyway since we cannot identify the referenced token
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3062);
throw new WSSecurityException("badReferenceURI");
}
if (!uri.startsWith("#")) {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R5204);
}
uri = WSSUtils.dropReferenceMarker(uri);
//referenced BST:*/
//we have to search BST somewhere in the doc. First we will check for a BST already processed and
//stored in the context. Otherwise we will abort now.
//prevent recursive key reference DOS:
Integer invokeCount = securityContext.<Integer>get("" + Thread.currentThread().hashCode());
if (invokeCount == null) {
invokeCount = 0;
}
invokeCount++;
if (invokeCount == 10) {
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN);
}
securityContext.put("" + Thread.currentThread().hashCode(), invokeCount);
SecurityTokenProvider securityTokenProvider = securityContext.getSecurityTokenProvider(uri);
if (securityTokenProvider == null) {
throw new WSSecurityException(WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, "noToken", uri);
}
if (securityTokenProvider.getSecurityToken() instanceof SecurityTokenReference) {
((WSSecurityContext) securityContext).handleBSPRule(WSSConstants.BSPRule.R3057);
}
return securityTokenProvider.getSecurityToken();
}
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "noKeyinfo");
} finally {
securityContext.remove("" + Thread.currentThread().hashCode());
}
}
public static SecurityToken getSecurityToken(KeyValueType keyValueType, final Crypto crypto,
final CallbackHandler callbackHandler, SecurityContext securityContext)
throws XMLSecurityException {
final RSAKeyValueType rsaKeyValueType
= XMLSecurityUtils.getQNameType(keyValueType.getContent(), WSSConstants.TAG_dsig_RSAKeyValue);
if (rsaKeyValueType != null) {
return new RsaKeyValueSecurityToken(rsaKeyValueType, (WSSecurityContext) securityContext,
callbackHandler, WSSConstants.WSSKeyIdentifierType.KEY_VALUE) {
@Override
public void verify() throws XMLSecurityException {
crypto.verifyTrust(getPubKey("", null));
}
};
}
final DSAKeyValueType dsaKeyValueType
= XMLSecurityUtils.getQNameType(keyValueType.getContent(), WSSConstants.TAG_dsig_DSAKeyValue);
if (dsaKeyValueType != null) {
return new DsaKeyValueSecurityToken(dsaKeyValueType, (WSSecurityContext) securityContext,
callbackHandler, WSSConstants.WSSKeyIdentifierType.KEY_VALUE) {
@Override
public void verify() throws XMLSecurityException {
crypto.verifyTrust(getPubKey("", null));
}
};
}
final ECKeyValueType ecKeyValueType
= XMLSecurityUtils.getQNameType(keyValueType.getContent(), WSSConstants.TAG_dsig11_ECKeyValue);
if (ecKeyValueType != null) {
return new ECKeyValueSecurityToken(ecKeyValueType, (WSSecurityContext) securityContext,
callbackHandler, WSSConstants.WSSKeyIdentifierType.KEY_VALUE) {
@Override
public void verify() throws XMLSecurityException {
crypto.verifyTrust(getPubKey("", null));
}
};
}
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "unsupportedKeyInfo");
}
public static SecurityToken getSecurityToken(
BinarySecurityTokenType binarySecurityTokenType, SecurityContext securityContext,
Crypto crypto, CallbackHandler callbackHandler) throws XMLSecurityException {
//only Base64Encoding is supported
if (!WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING.equals(binarySecurityTokenType.getEncodingType())) {
throw new WSSecurityException(
WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "badEncoding", binarySecurityTokenType.getEncodingType());
}
byte[] securityTokenData = Base64.decodeBase64(binarySecurityTokenType.getValue());
if (WSSConstants.NS_X509_V3_TYPE.equals(binarySecurityTokenType.getValueType())) {
return new X509_V3SecurityToken((WSSecurityContext) securityContext, crypto, callbackHandler,
securityTokenData, binarySecurityTokenType.getId(), WSSConstants.WSSKeyIdentifierType.SECURITY_TOKEN_DIRECT_REFERENCE);
} else if (WSSConstants.NS_X509PKIPathv1.equals(binarySecurityTokenType.getValueType())) {
return new X509PKIPathv1SecurityToken((WSSecurityContext) securityContext, crypto, callbackHandler,
securityTokenData, binarySecurityTokenType.getId(), WSSConstants.WSSKeyIdentifierType.SECURITY_TOKEN_DIRECT_REFERENCE);
} else {
throw new WSSecurityException(
WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "invalidValueType", binarySecurityTokenType.getValueType());
}
}
public static SecurityToken getSecurityToken(String username, String password, String created, byte[] nonce,
byte[] salt, Long iteration, WSSecurityContext wsSecurityContext,
String id) throws WSSecurityException {
return new UsernameSecurityToken(username, password, created, nonce, salt, iteration, wsSecurityContext, id, WSSConstants.WSSKeyIdentifierType.SECURITY_TOKEN_DIRECT_REFERENCE);
}
public static SecurityToken getSecurityToken(String referencedTokenId, Deque<XMLSecEvent> xmlSecEvents,
CallbackHandler callbackHandler,
SecurityContext securityContext, String id)
throws XMLSecurityException {
return new SecurityTokenReference(
securityContext.getSecurityTokenProvider(referencedTokenId).
getSecurityToken(), xmlSecEvents,
(WSSecurityContext) securityContext, callbackHandler, id, WSSConstants.WSSKeyIdentifierType.SECURITY_TOKEN_REFERENCE);
}
}