diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2018-06-26 11:03:48 +0200 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2018-06-26 11:03:48 +0200 |
commit | bee5dd259a4438d45ecd1bcc26dfba12875236d6 (patch) | |
tree | fe1cf7a35cd15dee5fb3c05de0341aa63bf743e0 /eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils | |
download | EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.gz EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.bz2 EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.zip |
initial commit
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils')
3 files changed, 367 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java new file mode 100644 index 00000000..40ad8a82 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java @@ -0,0 +1,201 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.impl.utils; + +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateKey; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.x509.X509Credential; +import org.opensaml.xml.signature.Signature; +import org.opensaml.xml.signature.SignatureConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.KeyStoreX509CredentialAdapter; + +public abstract class AbstractCredentialProvider { + + private static final Logger log = LoggerFactory.getLogger(AbstractCredentialProvider.class); + + private KeyStore keyStore = null; + + /** + * Get a friendlyName for this keyStore implementation + * This friendlyName is used for logging + * + * @return keyStore friendlyName + */ + public abstract String getFriendlyName(); + + /** + * Get KeyStore + * + * @return URL to the keyStore + * @throws EAAFException + */ + public abstract String getKeyStoreFilePath() throws EAAFException; + + /** + * Get keyStore password + * + * @return Password of the keyStore + */ + public abstract String getKeyStorePassword(); + + /** + * Get alias of key for metadata signing + * + * @return key alias + */ + public abstract String getMetadataKeyAlias(); + + /** + * Get password of key for metadata signing + * + * @return key password + */ + public abstract String getMetadataKeyPassword(); + + /** + * Get alias of key for request/response signing + * + * @return key alias + */ + public abstract String getSignatureKeyAlias(); + + /** + * Get password of key for request/response signing + * + * @return key password + */ + public abstract String getSignatureKeyPassword(); + + /** + * Get alias of key for IDP response encryption + * + * @return key alias + */ + public abstract String getEncryptionKeyAlias(); + + /** + * Get password of key for IDP response encryption + * + * @return key password + */ + public abstract String getEncryptionKeyPassword(); + + + public X509Credential getIDPMetaDataSigningCredential() + throws CredentialsNotAvailableException { + try { + + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter( + keyStore, getMetadataKeyAlias(), getMetadataKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.SIGNING); + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + log.error(getFriendlyName() + " Metadata Signing credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Signing credentials (Alias: " + + getMetadataKeyAlias() + ") is not found or contains no PrivateKey."}); + + } + return credentials; + } catch (Exception e) { + log.error("Failed to generate " + getFriendlyName() + " Metadata Signing credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e); + } + } + + public X509Credential getIDPAssertionSigningCredential() + throws CredentialsNotAvailableException { + try { + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter( + keyStore, getSignatureKeyAlias(), getSignatureKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.SIGNING); + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + log.error(getFriendlyName() + " Assertion Signing credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Signing credentials (Alias: " + + getSignatureKeyAlias() + ") is not found or contains no PrivateKey."}); + + } + + return (X509Credential) credentials; + } catch (Exception e) { + log.error("Failed to generate " + getFriendlyName() + " Assertion Signing credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e); + } + } + + public X509Credential getIDPAssertionEncryptionCredential() + throws CredentialsNotAvailableException { + try { + if (keyStore == null) + keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), + getKeyStorePassword()); + + //if no encryption key is configured return null + if (StringUtils.isEmpty(getEncryptionKeyAlias())) + return null; + + KeyStoreX509CredentialAdapter credentials = new KeyStoreX509CredentialAdapter( + keyStore, getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray()); + + credentials.setUsageType(UsageType.ENCRYPTION); + + if (credentials.getPrivateKey() == null && credentials.getSecretKey() == null) { + log.error(getFriendlyName() + " Assertion Encryption credentials is not found or contains no PrivateKey."); + throw new CredentialsNotAvailableException("config.27", new Object[]{getFriendlyName() + " Assertion Encryption credentials (Alias: " + + getEncryptionKeyAlias() + ") is not found or contains no PrivateKey."}); + + } + + return (X509Credential) credentials; + + } catch (Exception e) { + log.error("Failed to generate " + getFriendlyName() + " Assertion Encryption credentials"); + e.printStackTrace(); + throw new CredentialsNotAvailableException("config.27", new Object[]{e.getMessage()}, e); + } + } + + public static Signature getIDPSignature(Credential credentials) { + PrivateKey privatekey = credentials.getPrivateKey(); + Signature signer = SAML2Utils.createSAMLObject(Signature.class); + + if (privatekey instanceof RSAPrivateKey) { + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); + + } else if (privatekey instanceof ECPrivateKey) { + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256); + + } else { + log.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential."); + + + } + + signer.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + signer.setSigningCredential(credentials); + return signer; + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QAALevelVerifier.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QAALevelVerifier.java new file mode 100644 index 00000000..707f12e2 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/QAALevelVerifier.java @@ -0,0 +1,41 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.impl.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.core.api.data.EAAFConstants; +import at.gv.egiz.eaaf.modules.pvp2.exception.QAANotAllowedException; + +/** + * @author tlenz + * + */ +public class QAALevelVerifier { + + private static final Logger log = LoggerFactory.getLogger(QAALevelVerifier.class); + + public static void verifyQAALevel(String qaaAuth, String qaaRequest) throws QAANotAllowedException { + + if (EAAFConstants.EIDAS_QAA_LOW.equals(qaaRequest) && + (EAAFConstants.EIDAS_QAA_LOW.equals(qaaAuth) || + EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaAuth) || + EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth)) + ) + log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... "); + + else if (EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaRequest) && + (EAAFConstants.EIDAS_QAA_SUBSTANTIAL.equals(qaaAuth) || + EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth)) + ) + log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... "); + + else if (EAAFConstants.EIDAS_QAA_HIGH.equals(qaaRequest) && EAAFConstants.EIDAS_QAA_HIGH.equals(qaaAuth)) + log.debug("Requesed LoA fits LoA from authentication. Continue auth process ... "); + + else + throw new QAANotAllowedException(qaaAuth, qaaRequest); + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SAML2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SAML2Utils.java new file mode 100644 index 00000000..1da3fea3 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/SAML2Utils.java @@ -0,0 +1,125 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.impl.utils; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.opensaml.Configuration; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.ws.soap.soap11.Body; +import org.opensaml.ws.soap.soap11.Envelope; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.w3c.dom.Document; + +import at.gv.egiz.eaaf.core.impl.utils.Random; + +public class SAML2Utils { + + public static <T> T createSAMLObject(final Class<T> clazz) { + try { + XMLObjectBuilderFactory builderFactory = Configuration + .getBuilderFactory(); + + QName defaultElementName = (QName) clazz.getDeclaredField( + "DEFAULT_ELEMENT_NAME").get(null); + @SuppressWarnings("unchecked") + T object = (T) builderFactory.getBuilder(defaultElementName) + .buildObject(defaultElementName); + return object; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } + + public static String getSecureIdentifier() { + return "_".concat(Random.nextHexRandom16()); + + /*Bug-Fix: There are open problems with RandomNumberGenerator via Java SPI and Java JDK 8.121 + * Generation of a 16bit Random identifier FAILES with an Caused by: java.lang.ArrayIndexOutOfBoundsException + * Caused by: java.lang.ArrayIndexOutOfBoundsException + at iaik.security.random.o.engineNextBytes(Unknown Source) + at iaik.security.random.SecRandomSpi.engineNextBytes(Unknown Source) + at java.security.SecureRandom.nextBytes(SecureRandom.java:468) + at org.opensaml.common.impl.SecureRandomIdentifierGenerator.generateIdentifier(SecureRandomIdentifierGenerator.java:62) + at org.opensaml.common.impl.SecureRandomIdentifierGenerator.generateIdentifier(SecureRandomIdentifierGenerator.java:56) + at at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils.getSecureIdentifier(SAML2Utils.java:69) + */ + //return idGenerator.generateIdentifier(); + } + + private static SecureRandomIdentifierGenerator idGenerator; + + private static DocumentBuilder builder; + static { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + try { + idGenerator = new SecureRandomIdentifierGenerator(); + } catch(NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + public static Document asDOMDocument(XMLObject object) throws IOException, + MarshallingException, TransformerException { + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory().getMarshaller( + object); + out.marshall(object, document); + return document; + } + + public static Status getSuccessStatus() { + Status status = SAML2Utils.createSAMLObject(Status.class); + StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); + statusCode.setValue(StatusCode.SUCCESS_URI); + status.setStatusCode(statusCode); + return status; + } + + public static int getDefaultAssertionConsumerServiceIndex(SPSSODescriptor spSSODescriptor) { + + List<AssertionConsumerService> assertionConsumerList = spSSODescriptor.getAssertionConsumerServices(); + + for (AssertionConsumerService el : assertionConsumerList) { + if (el.isDefault()) + return el.getIndex(); + + } + + return 0; + } + + public static Envelope buildSOAP11Envelope(XMLObject payload) { + XMLObjectBuilderFactory bf = Configuration.getBuilderFactory(); + Envelope envelope = (Envelope) bf.getBuilder(Envelope.DEFAULT_ELEMENT_NAME).buildObject(Envelope.DEFAULT_ELEMENT_NAME); + Body body = (Body) bf.getBuilder(Body.DEFAULT_ELEMENT_NAME).buildObject(Body.DEFAULT_ELEMENT_NAME); + + body.getUnknownXMLObjects().add(payload); + envelope.setBody(body); + + return envelope; + } +} |