View Javadoc

1   /*
2    * Licensed to the University Corporation for Advanced Internet Development, 
3    * Inc. (UCAID) under one or more contributor license agreements.  See the 
4    * NOTICE file distributed with this work for additional information regarding
5    * copyright ownership. The UCAID licenses this file to You under the Apache 
6    * License, Version 2.0 (the "License"); you may not use this file except in 
7    * compliance with the License.  You may obtain a copy of the License at
8    *
9    *    http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.principalConnector;
19  
20  import org.opensaml.common.SAMLObject;
21  import org.opensaml.saml1.core.NameIdentifier;
22  import org.opensaml.saml2.core.NameID;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
27  import edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.ShibbolethResolutionContext;
28  import edu.internet2.middleware.shibboleth.common.profile.provider.SAMLProfileRequestContext;
29  import edu.internet2.middleware.shibboleth.common.util.DataExpiredException;
30  import edu.internet2.middleware.shibboleth.common.util.DataSealer;
31  import edu.internet2.middleware.shibboleth.common.util.DataSealerException;
32  
33  /**
34   * A principal connector that attempts to look up a name identifier within a store.
35   */
36  public class CryptoTransientPrincipalConnector extends BasePrincipalConnector {
37  
38      /** Class logger. */
39      private static Logger log = LoggerFactory.getLogger(CryptoTransientPrincipalConnector.class);
40  
41      /** Object used to protect and encrypt the data. */
42      private DataSealer dataSealer;
43      
44      /**
45       * Constructor.
46       * 
47       * @param sealer object used to protect and encrypt the data
48       */
49      public CryptoTransientPrincipalConnector(DataSealer sealer) {
50          if (sealer == null) {
51              throw new IllegalArgumentException("DataSealer may not be null.");
52          }
53          dataSealer = sealer;
54      }
55  
56      /** {@inheritDoc} */
57      public String resolve(ShibbolethResolutionContext resolutionContext) throws AttributeResolutionException {
58          SAMLProfileRequestContext<?, ?, ?, ?> requestContext = resolutionContext.getAttributeRequestContext();
59  
60          String transientId = null;
61          String nameQualifier = null;
62          String spNameQualifier = null;
63          SAMLObject subjectId = requestContext.getSubjectNameIdentifier();
64          if (subjectId instanceof NameIdentifier) {
65              NameIdentifier nameId = (NameIdentifier) requestContext.getSubjectNameIdentifier();
66              if (nameId != null) {
67                  transientId = nameId.getNameIdentifier();
68                  nameQualifier = nameId.getNameQualifier();
69              }
70          } else if (requestContext.getSubjectNameIdentifier() instanceof NameID) {
71              NameID nameId = (NameID) requestContext.getSubjectNameIdentifier();
72              if (nameId != null) {
73                  transientId = nameId.getValue();
74                  nameQualifier = nameId.getNameQualifier();
75                  spNameQualifier = nameId.getSPNameQualifier();
76              }
77          } else {
78              throw new AttributeResolutionException("Subject name identifier is not of a supported type");
79          }
80  
81          if (transientId == null) {
82              throw new AttributeResolutionException("Invalid subject name identifier");
83          }
84  
85          String decodedId;
86          try {
87              decodedId = dataSealer.unwrap(transientId);
88          } catch (DataExpiredException e) {
89              throw new AttributeResolutionException("Principal identifier has expired.");
90          } catch (DataSealerException e) {
91              throw new AttributeResolutionException("Caught exception unwrapping principal identifier.", e);
92          }
93          
94          if (decodedId == null) {
95              throw new AttributeResolutionException("Unable to recover principal from transient identifier: "
96                      + transientId);
97          }
98          
99          // Split the identifier.
100         String[] parts = decodedId.split("!");
101         if (parts.length != 3) {
102             throw new AttributeResolutionException("Decoded principal information was invalid: "
103                     + decodedId);
104         }
105         
106         if (nameQualifier != null && !nameQualifier.equals(parts[0])) {
107             throw new AttributeResolutionException("Decoded NameQualifier (" + nameQualifier +
108                     ") does not match supplied value (" + parts[0] + ").");
109         } else if (spNameQualifier != null && !spNameQualifier.equals(parts[1])) {
110             throw new AttributeResolutionException("Decoded SPNameQualifier (" + spNameQualifier +
111                     ") does not match supplied value (" + parts[1] + ").");
112         } else if (!parts[0].equals(requestContext.getOutboundMessageIssuer())) {
113             throw new AttributeResolutionException("Decoded NameQualifier (" + parts[0] +
114                     ") does not match issuer (" + requestContext.getOutboundMessageIssuer() + ").");
115         } else if (!parts[1].equals(requestContext.getInboundMessageIssuer())) {
116             throw new AttributeResolutionException("Decoded SPNameQualifier (" + parts[0] +
117                     ") does not match requester (" + requestContext.getInboundMessageIssuer() + ").");
118         }
119 
120         return parts[2];
121     }
122 
123     /** {@inheritDoc} */
124     public void validate() throws AttributeResolutionException {
125         if (dataSealer == null) {
126             log.error("CryptoTransientPrincipalConnector (" + getId()
127                     + ") must have a DataSealer object set.");
128             throw new AttributeResolutionException("CryptoTransientPrincipalConnector (" + getId()
129                     + ") must have a DataSealer object set.");
130         }
131     }
132 }