Skip to content

Instantly share code, notes, and snippets.

@serac
Last active August 29, 2015 14:20
Show Gist options
  • Save serac/e3c33ebf83a99f8423f3 to your computer and use it in GitHub Desktop.
Save serac/e3c33ebf83a99f8423f3 to your computer and use it in GitHub Desktop.
Custom OpenSAML trust engine for enforcing certificate policies are satisfied
package edu.vt.middleware.idp.authn;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.cryptacular.x509.ExtensionReader;
import org.opensaml.security.trust.TrustEngine;
import org.opensaml.security.x509.X509Credential;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Trust engine that ensures certificates satisfy one or more policies found on the <em>CertificatePolicies</em>
* X.509 extension field.
*
* @author Marvin S. Addison
*/
public class PolicyTrustEngine implements TrustEngine<X509Credential> {
/** Logger instance. */
private final Logger logger = LoggerFactory.getLogger(PolicyTrustEngine.class);
/** Requisite policies that must be satisfied. */
private final List<String> requiredPolicyOids;
/**
* Creates a new trust engine instance that enforces existence of given policy OIDs on candidate certificates.
*
* @param policyOids List of certificate policy OIDs that must be present on candidate certificates.
*/
public PolicyTrustEngine(@NotEmpty final List<String> policyOids) {
requiredPolicyOids = (List<String>) Constraint.isNotEmpty(policyOids, "Policy OIDs cannot be null or empty");
}
@Override
public boolean validate(
@Nonnull X509Credential x509Credential,
@Nullable CriteriaSet criterions) throws SecurityException {
final ExtensionReader reader = new ExtensionReader(x509Credential.getEntityCertificate());
final List<PolicyInformation> policies = reader.readCertificatePolicies();
if (policies != null) {
final List<String> policyOids = policyOids(policies);
logger.debug("Found certificate policies: {}", policyOids);
policyOids.retainAll(requiredPolicyOids);
if (policyOids.size() == requiredPolicyOids.size()) {
return true;
}
} else {
logger.debug("No certificate policies found");
}
return false;
}
private List<String> policyOids(final List<PolicyInformation> policies) {
if (policies.size() == 0) {
return Collections.emptyList();
}
final List<String> oids = new ArrayList<>(policies.size());
for (PolicyInformation policy : policies) {
oids.add(policy.getPolicyIdentifier().getId());
}
return oids;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize"
default-destroy-method="destroy">
<!-- Servlet context-relative path to wherever your implementation lives. -->
<bean id="shibboleth.authn.X509.externalAuthnPath" class="java.lang.String"
c:_0="contextRelative:x509-prompt.jsp" />
<!-- Custom trust engine for InCommon assurance -->
<bean id="shibboleth.authn.X509.TrustEngine"
class="edu.vt.middleware.idp.authn.PolicyTrustEngine"
c:policyOids="#{{'1.2.3.4'}}" />
<!-- Populate RP UI info from metadata? -->
<util:constant id="shibboleth.authn.X509.populateUIInfo" static-field="java.lang.Boolean.TRUE" />
<!--
Define entries here to map error messages returned by external modules and classify them as particular
kinds of errors for use in your templates and as events in flows.
The examples here just allow external signaling of an exact condition.
If you want to "fall-through" to other login flows, include a mapping to "ReselectFlow".
-->
<util:map id="shibboleth.authn.X509.ClassifiedMessageMap">
<entry key="NoCredentials">
<list>
<value>SetRPUIInformation</value>
</list>
</entry>
<entry key="InvalidCredentials">
<list>
<value>SetRPUIInformation</value>
</list>
</entry>
</util:map>
</beans>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment