2 * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.] Licensed under the Apache License,
3 * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy
4 * of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
5 * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
6 * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
7 * limitations under the License.
10 package edu.internet2.middleware.shibboleth.idp;
14 import java.security.Principal;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Iterator;
19 import org.apache.log4j.Logger;
20 import org.apache.xml.security.signature.XMLSignature;
21 import org.opensaml.InvalidCryptoException;
22 import org.opensaml.SAMLAssertion;
23 import org.opensaml.SAMLAttribute;
24 import org.opensaml.SAMLException;
25 import org.opensaml.SAMLResponse;
26 import org.opensaml.artifact.Artifact;
27 import org.w3c.dom.Element;
29 import edu.internet2.middleware.shibboleth.aa.AAAttribute;
30 import edu.internet2.middleware.shibboleth.aa.AAAttributeSet;
31 import edu.internet2.middleware.shibboleth.aa.AAException;
32 import edu.internet2.middleware.shibboleth.aa.arp.ArpEngine;
33 import edu.internet2.middleware.shibboleth.aa.arp.ArpProcessingException;
34 import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolver;
35 import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
36 import edu.internet2.middleware.shibboleth.common.Credential;
37 import edu.internet2.middleware.shibboleth.common.NameMapper;
38 import edu.internet2.middleware.shibboleth.common.RelyingParty;
39 import edu.internet2.middleware.shibboleth.common.ServiceProviderMapper;
40 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
41 import edu.internet2.middleware.shibboleth.common.Trust;
42 import edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust;
43 import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
44 import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
45 import edu.internet2.middleware.shibboleth.metadata.Metadata;
46 import edu.internet2.middleware.shibboleth.metadata.MetadataException;
49 * Delivers core IdP functionality (Attribute resolution, ARP filtering, Metadata lookup, Signing, Mapping between local &
50 * SAML identifiers, etc.) to components that process protocol-specific requests.
52 * @author Walter Hoehn
54 public class IdPProtocolSupport implements Metadata {
56 private static Logger log = Logger.getLogger(IdPProtocolSupport.class.getName());
57 private Logger transactionLog;
58 private IdPConfig config;
59 private ArrayList metadata = new ArrayList();
60 private NameMapper nameMapper;
61 private ServiceProviderMapper spMapper;
62 private ArpEngine arpEngine;
63 private AttributeResolver resolver;
64 private ArtifactMapper artifactMapper;
65 private Semaphore throttle;
66 private Trust trust = new ShibbolethTrust();
68 IdPProtocolSupport(IdPConfig config, Logger transactionLog, NameMapper nameMapper, ServiceProviderMapper spMapper,
69 ArpEngine arpEngine, AttributeResolver resolver, ArtifactMapper artifactMapper)
70 throws ShibbolethConfigurationException {
72 this.transactionLog = transactionLog;
74 this.nameMapper = nameMapper;
75 this.spMapper = spMapper;
76 spMapper.setMetadata(this);
77 this.arpEngine = arpEngine;
78 this.resolver = resolver;
79 this.artifactMapper = artifactMapper;
81 // Load a semaphore that throttles how many requests the IdP will handle at once
82 throttle = new Semaphore(config.getMaxThreads());
85 public Logger getTransactionLog() {
87 return transactionLog;
90 public IdPConfig getIdPConfig() {
95 public NameMapper getNameMapper() {
100 public ServiceProviderMapper getServiceProviderMapper() {
105 public void signAssertions(SAMLAssertion[] assertions, RelyingParty relyingParty) throws InvalidCryptoException,
108 if (relyingParty.getIdentityProvider().getSigningCredential() == null
109 || relyingParty.getIdentityProvider().getSigningCredential().getPrivateKey() == null) { throw new InvalidCryptoException(
110 SAMLException.RESPONDER, "Invalid signing credential."); }
112 for (int i = 0; i < assertions.length; i++) {
113 String assertionAlgorithm;
114 if (relyingParty.getIdentityProvider().getSigningCredential().getCredentialType() == Credential.RSA) {
115 assertionAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
116 } else if (relyingParty.getIdentityProvider().getSigningCredential().getCredentialType() == Credential.DSA) {
117 assertionAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_DSA;
119 throw new InvalidCryptoException(SAMLException.RESPONDER,
120 "The Shibboleth IdP currently only supports signing with RSA and DSA keys.");
125 assertions[i].sign(assertionAlgorithm, relyingParty.getIdentityProvider().getSigningCredential()
126 .getPrivateKey(), Arrays.asList(relyingParty.getIdentityProvider().getSigningCredential()
127 .getX509CertificateChain()));
134 public void signResponse(SAMLResponse response, RelyingParty relyingParty) throws SAMLException {
136 // Make sure we have an appropriate credential
137 if (relyingParty.getIdentityProvider().getSigningCredential() == null
138 || relyingParty.getIdentityProvider().getSigningCredential().getPrivateKey() == null) { throw new InvalidCryptoException(
139 SAMLException.RESPONDER, "Invalid signing credential."); }
142 String responseAlgorithm;
143 if (relyingParty.getIdentityProvider().getSigningCredential().getCredentialType() == Credential.RSA) {
144 responseAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
145 } else if (relyingParty.getIdentityProvider().getSigningCredential().getCredentialType() == Credential.DSA) {
146 responseAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_DSA;
148 throw new InvalidCryptoException(SAMLException.RESPONDER,
149 "The Shibboleth IdP currently only supports signing with RSA and DSA keys.");
153 response.sign(responseAlgorithm, relyingParty.getIdentityProvider().getSigningCredential().getPrivateKey(),
154 Arrays.asList(relyingParty.getIdentityProvider().getSigningCredential().getX509CertificateChain()));
160 protected void addMetadataProvider(Element element) {
162 log.debug("Found Metadata Provider configuration element.");
163 if (!element.getTagName().equals("MetadataProvider")) {
164 log.error("Error while attemtping to load Metadata Provider. Malformed provider specificaion.");
169 metadata.add(MetadataProviderFactory.loadProvider(element));
170 } catch (MetadataException e) {
171 log.error("Unable to load Metadata Provider. Skipping...");
175 public int providerCount() {
177 return metadata.size();
180 public EntityDescriptor lookup(String providerId, boolean strict) {
182 Iterator iterator = metadata.iterator();
183 while (iterator.hasNext()) {
184 EntityDescriptor provider = ((Metadata) iterator.next()).lookup(providerId);
185 if (provider != null) { return provider; }
190 public EntityDescriptor lookup(Artifact artifact, boolean strict) {
192 Iterator iterator = metadata.iterator();
193 while (iterator.hasNext()) {
194 EntityDescriptor provider = ((Metadata) iterator.next()).lookup(artifact);
195 if (provider != null) { return provider; }
200 public EntityDescriptor lookup(String id) {
202 return lookup(id, true);
205 public EntityDescriptor lookup(Artifact artifact) {
207 return lookup(artifact, true);
210 public EntityDescriptor getRootEntity() {
215 public EntitiesDescriptor getRootEntities() {
220 public SAMLAttribute[] getReleaseAttributes(Principal principal, RelyingParty relyingParty, String requester,
221 URL resource) throws AAException {
224 URI[] potentialAttributes = arpEngine.listPossibleReleaseAttributes(principal, requester, resource);
225 return getReleaseAttributes(principal, relyingParty, requester, resource, potentialAttributes);
227 } catch (ArpProcessingException e) {
228 log.error("An error occurred while processing the ARPs for principal (" + principal.getName() + ") :"
230 throw new AAException("Error retrieving data for principal.");
234 public SAMLAttribute[] getReleaseAttributes(Principal principal, RelyingParty relyingParty, String requester,
235 URL resource, URI[] attributeNames) throws AAException {
238 AAAttributeSet attributeSet = new AAAttributeSet();
239 for (int i = 0; i < attributeNames.length; i++) {
241 AAAttribute attribute = null;
242 if (relyingParty.wantsSchemaHack()) {
243 attribute = new AAAttribute(attributeNames[i].toString(), true);
245 attribute = new AAAttribute(attributeNames[i].toString(), false);
248 attributeSet.add(attribute);
251 return resolveAttributes(principal, requester, relyingParty.getIdentityProvider().getProviderId(),
252 resource, attributeSet);
254 } catch (SAMLException e) {
255 log.error("An error occurred while creating attributes for principal (" + principal.getName() + ") :"
257 throw new AAException("Error retrieving data for principal.");
259 } catch (ArpProcessingException e) {
260 log.error("An error occurred while processing the ARPs for principal (" + principal.getName() + ") :"
262 throw new AAException("Error retrieving data for principal.");
266 public SAMLAttribute[] resolveAttributes(Principal principal, String requester, String responder, URL resource,
267 AAAttributeSet attributeSet) throws ArpProcessingException {
269 resolver.resolveAttributes(principal, requester, responder, attributeSet);
270 arpEngine.filterAttributes(attributeSet, principal, requester, resource);
271 return attributeSet.getAttributes();
274 public SAMLAttribute[] resolveAttributesNoPolicies(Principal principal, String requester, String responder,
275 URL resource, AAAttributeSet attributeSet) throws ArpProcessingException {
277 resolver.resolveAttributes(principal, requester, responder, attributeSet);
278 arpEngine.filterAttributes(attributeSet, principal, requester, resource);
279 return attributeSet.getAttributes();
283 * Cleanup resources that won't be released when this object is garbage-collected
285 public void destroy() {
291 public ArtifactMapper getArtifactMapper() {
293 return artifactMapper;
296 public Trust getTrust() {
301 private class Semaphore {
305 public Semaphore(int value) {
310 public synchronized void enter() {
316 } catch (InterruptedException e) {
317 // squelch and continue
322 public synchronized void exit() {