Skip to content

Commit

Permalink
SES-88 Adding support for MetaIOP / PKIX in SSL/TLS connections.
Browse files Browse the repository at this point in the history
  • Loading branch information
vschafer committed Apr 11, 2011
1 parent b4f19c3 commit f27021c
Show file tree
Hide file tree
Showing 15 changed files with 456 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver;
import org.opensaml.xml.security.trust.ExplicitX509CertificateTrustEngine;
import org.opensaml.xml.security.trust.TrustEngine;
import org.opensaml.xml.security.x509.PKIXX509CredentialTrustEngine;
import org.opensaml.xml.security.x509.X509Credential;
import org.opensaml.xml.signature.SignatureTrustEngine;
import org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine;
import org.opensaml.xml.signature.impl.PKIXSignatureTrustEngine;
Expand Down Expand Up @@ -83,20 +87,9 @@ public class SAMLContextProviderImpl implements SAMLContextProvider, Initializin
*/
public SAMLMessageContext getLocalEntity(HttpServletRequest request, HttpServletResponse response) throws MetadataProviderException {

HttpServletRequestAdapter inTransport = new HttpServletRequestAdapter(request);
HttpServletResponseAdapter outTransport = new HttpServletResponseAdapter(response, false);

SAMLMessageContext context = new SAMLMessageContext();

context.setMetadataProvider(metadata);
context.setInboundMessageTransport(inTransport);
context.setOutboundMessageTransport(outTransport);

populateEntityId(context, request.getContextPath());
populateLocalEntity(context);
populateDecrypter(context);
populateTrustEngine(context);

populateContext(request, response, context);
return context;

}
Expand All @@ -113,21 +106,27 @@ public SAMLMessageContext getLocalEntity(HttpServletRequest request, HttpServlet
*/
public SAMLMessageContext getLocalEntity(HttpServletRequest request, HttpServletResponse response, SAMLCredential credential) throws MetadataProviderException {

SAMLMessageContext context = new SAMLMessageContext();
populateEntityId(context, credential);
populateContext(request, response, context);
return context;

}

private void populateContext(HttpServletRequest request, HttpServletResponse response, SAMLMessageContext context) throws MetadataProviderException {

HttpServletRequestAdapter inTransport = new HttpServletRequestAdapter(request);
HttpServletResponseAdapter outTransport = new HttpServletResponseAdapter(response, false);

SAMLMessageContext context = new SAMLMessageContext();

context.setMetadataProvider(metadata);
context.setInboundMessageTransport(inTransport);
context.setOutboundMessageTransport(outTransport);

populateEntityId(context, credential);
populateLocalEntity(context);
populateDecrypter(context);
populateSSLCredential(context);
populateTrustEngine(context);

return context;
populateSSLTrustEngine(context);

}

Expand Down Expand Up @@ -240,6 +239,25 @@ private void populateLocalEntity(SAMLMessageContext samlContext) throws Metadata

}

/**
* Populates X509 Credential used to authenticate this machine against peer servers. Uses key with alias specified
* in extended metadata under TlsKey, when not set uses the default credential.
*
* @param samlContext context to populate
*/
protected void populateSSLCredential(SAMLMessageContext samlContext) {

X509Credential tlsCredential;
if (samlContext.getLocalExtendedMetadata().getTlsKey() != null) {
tlsCredential = (X509Credential) keyManager.getCredential(samlContext.getLocalExtendedMetadata().getTlsKey());
} else {
tlsCredential = (X509Credential) keyManager.getDefaultCredential();
}

samlContext.setLocalSSLCredential(tlsCredential);

}

/**
* Populates a decrypter based on settings in the extended metadata or using a default credential when no
* encryption credential is specified in the extended metadata.
Expand Down Expand Up @@ -285,6 +303,23 @@ protected void populateTrustEngine(SAMLMessageContext samlContext) {
samlContext.setLocalTrustEngine(engine);
}

/**
* Based on the settings in the extended metadata either creates a PKIX trust engine with trusted keys specified
* in the extended metadata as anchors or (by default) an explicit trust engine using data from the metadata or
* from the values overriden in the ExtendedMetadata. The trust engine is used to verify SSL connections.
*
* @param samlContext context to populate
*/
protected void populateSSLTrustEngine(SAMLMessageContext samlContext) {
TrustEngine<X509Credential> engine;
if ("pkix".equalsIgnoreCase(samlContext.getLocalExtendedMetadata().getSecurityProfile())) {
engine = new PKIXX509CredentialTrustEngine(pkixResolver);
} else {
engine = new ExplicitX509CertificateTrustEngine(metadataResolver);
}
samlContext.setLocalSSLTrustEngine(engine);
}

@Autowired
public void setMetadata(MetadataManager metadata) {
this.metadata = metadata;
Expand All @@ -306,6 +341,8 @@ public void afterPropertiesSet() throws ServletException {
Assert.notNull(metadata, "Metadata must be set");

metadataResolver = new MetadataCredentialResolver(metadata, keyManager);
metadataResolver.setMeetAllCriteria(false);
metadataResolver.setUnevaluableSatisfies(true);
pkixResolver = new PKIXInformationResolver(metadataResolver, metadata, keyManager);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.saml2.encryption.Decrypter;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.trust.TrustEngine;
import org.opensaml.xml.security.x509.X509Credential;
import org.opensaml.xml.signature.SignatureTrustEngine;
import org.springframework.security.saml.metadata.ExtendedMetadata;

Expand All @@ -28,31 +30,19 @@
*/
public class SAMLMessageContext extends BasicSAMLMessageContext {

/**
* Object capable of decrypting data signed for this entity.
*/
private Decrypter localDecrypter;

/**
* Credential used to sign messages sent from this entity.
*/
private Credential localSigningCredential;

/**
* Extended metadata of the local entity
*/
private ExtendedMetadata localExtendedMetadata;

/**
* Extended metadata of the peer entity
*/
private SignatureTrustEngine localTrustEngine;
private TrustEngine<X509Credential> localSSLTrustEngine;
private X509Credential localSSLCredential;
private ExtendedMetadata peerExtendedMetadata;

/**
* Mechanism able to determine whether incoming message signature should be trusted.
* Extended metadata of the local entity
*
* @return local extended metadata
*/
private SignatureTrustEngine localTrustEngine;

public ExtendedMetadata getLocalExtendedMetadata() {
return localExtendedMetadata;
}
Expand All @@ -61,6 +51,11 @@ public void setLocalExtendedMetadata(ExtendedMetadata localExtendedMetadata) {
this.localExtendedMetadata = localExtendedMetadata;
}

/**
* Extended metadata of the peer entity.
*
* @return metadata
*/
public ExtendedMetadata getPeerExtendedMetadata() {
return peerExtendedMetadata;
}
Expand All @@ -69,6 +64,11 @@ public void setPeerExtendedMetadata(ExtendedMetadata peerExtendedMetadata) {
this.peerExtendedMetadata = peerExtendedMetadata;
}

/**
* Object capable of decrypting data signed for this entity.
*
* @return decrypter
*/
public Decrypter getLocalDecrypter() {
return localDecrypter;
}
Expand All @@ -77,6 +77,11 @@ public void setLocalDecrypter(Decrypter localDecrypter) {
this.localDecrypter = localDecrypter;
}

/**
* Mechanism able to determine whether incoming message signature should be trusted.
*
* @return trust engine used for verification of signatures coming from peers
*/
public SignatureTrustEngine getLocalTrustEngine() {
return localTrustEngine;
}
Expand All @@ -85,6 +90,11 @@ public void setLocalTrustEngine(SignatureTrustEngine localTrustEngine) {
this.localTrustEngine = localTrustEngine;
}

/**
* Credential used to sign messages sent from this entity.
*
* @return credential
*/
public Credential getLocalSigningCredential() {
return localSigningCredential;
}
Expand All @@ -93,4 +103,30 @@ public void setLocalSigningCredential(Credential localSigningCredential) {
this.localSigningCredential = localSigningCredential;
}

/**
* Trust engine used to verify server certificate in SSL/TLS connections.
*
* @return engine
*/
public TrustEngine<X509Credential> getLocalSSLTrustEngine() {
return localSSLTrustEngine;
}

public void setLocalSSLTrustEngine(TrustEngine<X509Credential> localSSLTrustEngine) {
this.localSSLTrustEngine = localSSLTrustEngine;
}

/**
* Credential used to authenticate this instance against peers using SSL/TLS .
*
* @return credential
*/
public X509Credential getLocalSSLCredential() {
return localSSLCredential;
}

public void setLocalSSLCredential(X509Credential localSSLCredential) {
this.localSSLCredential = localSSLCredential;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,26 @@ public void setRequireArtifactResolveSigned(boolean requireArtifactResolveSigned
this.requireArtifactResolveSigned = requireArtifactResolveSigned;
}

/**
* Key used to authenticate instance against remote servers.
*
* @return tls key
*/
public String getTlsKey() {
return tlsKey;
}

/**
* Alias of the key used to authenticate this instance against peer servers using SSL/TLS connections. When
* not set default credential will be used. Alias must be associated with a key containing a private key and being
* of X509 type.
*
* @param tlsKey tls key
*/
public void setTlsKey(String tlsKey) {
this.tlsKey = tlsKey;
}

/**
* Trusted keys usable for signature and server SSL/TLS verification for entities with PKIX verification enabled.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class MetadataGenerator implements ApplicationContextAware {

private String signingKey = null;
private String encryptionKey = null;
private String tlsKey = null;

private Collection<String> nameID = null;
private Collection<String> bindings = null;
Expand Down Expand Up @@ -98,14 +99,13 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
this.applicationContext = applicationContext;
}

protected KeyInfo getServerKeyInfo() {
// TODO add TLS key
Credential serverCredential = keyManager.getCredential(signingKey);
return generateKeyInfoForCredential(serverCredential);
}

protected KeyInfo getServerEncryptionKeyInfo() {
Credential serverCredential = keyManager.getCredential(encryptionKey);
protected KeyInfo getServerKeyInfo(String alias) {
Credential serverCredential = keyManager.getCredential(alias);
if (serverCredential == null) {
throw new RuntimeException("Key for alias " + alias + " not found");
} else if (serverCredential.getPrivateKey() == null) {
throw new RuntimeException("Key with alias " + alias + " doesn't have a private key");
}
return generateKeyInfoForCredential(serverCredential);
}

Expand All @@ -125,6 +125,7 @@ public void generateExtendedMetadata(ExtendedMetadata metadata) {
metadata.setEncryptionKey(encryptionKey);
metadata.setSigningKey(signingKey);
metadata.setAlias(entityAlias);
metadata.setTlsKey(tlsKey);
metadata.setLocal(true);
}

Expand Down Expand Up @@ -207,8 +208,13 @@ protected SPSSODescriptor buildSPSSODescriptor(String entityBaseURL, String enti
}

// Generate key info
spDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.SIGNING, getServerKeyInfo()));
spDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.ENCRYPTION, getServerEncryptionKeyInfo()));
spDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.SIGNING, getServerKeyInfo(signingKey)));
spDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.ENCRYPTION, getServerKeyInfo(encryptionKey)));

// Include TLS key with unspecified usage in case it differs from the singing and encryption keys
if (tlsKey != null && !(tlsKey.equals(encryptionKey)) && !(tlsKey.equals(signingKey))) {
spDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.UNSPECIFIED, getServerKeyInfo(tlsKey)));
}

return spDescriptor;

Expand Down Expand Up @@ -465,4 +471,12 @@ public String getEntityId() {
return entityId;
}

public String getTlsKey() {
return tlsKey;
}

public void setTlsKey(String tlsKey) {
this.tlsKey = tlsKey;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ public void refreshMetadata() {
@Override
public void addMetadataProvider(MetadataProvider newProvider) throws MetadataProviderException {

if (newProvider == null) {
throw new IllegalArgumentException("Null provider can't be added");
}

try {

lock.writeLock().lock();
Expand All @@ -276,21 +280,11 @@ public void addMetadataProvider(MetadataProvider newProvider) throws MetadataPro

}


private ExtendedMetadataDelegate getWrappedProvider(MetadataProvider provider) {
if (!(provider instanceof ExtendedMetadataDelegate)) {
log.debug("Wrapping metadata provider {} with extendedMetadataDelegate", provider);
return new ExtendedMetadataDelegate(provider);
} else {
return (ExtendedMetadataDelegate) provider;
}
}

@Override
public void removeMetadataProvider(MetadataProvider provider) {

if (provider == null) {
return;
throw new IllegalArgumentException("Null provider can't be removed");
}

try {
Expand All @@ -309,6 +303,15 @@ public void removeMetadataProvider(MetadataProvider provider) {

}

private ExtendedMetadataDelegate getWrappedProvider(MetadataProvider provider) {
if (!(provider instanceof ExtendedMetadataDelegate)) {
log.debug("Wrapping metadata provider {} with extendedMetadataDelegate", provider);
return new ExtendedMetadataDelegate(provider);
} else {
return (ExtendedMetadataDelegate) provider;
}
}

/**
* Method is expected to make sure that the provider is properly initialized. Also all loaded filters should get
* applied.
Expand Down
Loading

0 comments on commit f27021c

Please sign in to comment.