Rationalized support for artifact lookup in the union IdP.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / artifact / provider / BaseArtifactMapper.java
1 /*
2  * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
3  * All rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted
4  * provided that the following conditions are met: Redistributions of source code must retain the above copyright
5  * notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above
6  * copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials
7  * provided with the distribution, if any, must include the following acknowledgment: "This product includes software
8  * developed by the University Corporation for Advanced Internet Development <http://www.ucaid.edu> Internet2 Project.
9  * Alternately, this acknowledegement may appear in the software itself, if and wherever such third-party
10  * acknowledgments normally appear. Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor
11  * the University Corporation for Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote
12  * products derived from this software without specific prior written permission. For written permission, please contact
13  * shibboleth@shibboleth.org Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the
14  * University Corporation for Advanced Internet Development, nor may Shibboleth appear in their name, without prior
15  * written permission of the University Corporation for Advanced Internet Development. THIS SOFTWARE IS PROVIDED BY THE
16  * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE
18  * DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO
19  * EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC.
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 package edu.internet2.middleware.shibboleth.artifact.provider;
27
28 import java.io.IOException;
29 import java.security.MessageDigest;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.SecureRandom;
32
33 import org.apache.log4j.Logger;
34 import org.opensaml.SAMLAssertion;
35
36 import sun.misc.BASE64Decoder;
37 import sun.misc.BASE64Encoder;
38 import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
39 import edu.internet2.middleware.shibboleth.artifact.ArtifactMapping;
40 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
41 import edu.internet2.middleware.shibboleth.hs.HSRelyingParty;
42
43 /**
44  * Functionality common to most <code>ArtifactMapper</code> implementations, including creation and basic
45  * encoding/decoding of arifiacts. Defers storage and lookup to subclasses.
46  * 
47  * @author Walter Hoehn
48  */
49 public abstract class BaseArtifactMapper implements ArtifactMapper {
50
51         private static Logger   log                     = Logger.getLogger(BaseArtifactMapper.class.getName());
52         private static byte[]   typeCode        = {0, 1};
53
54         private SecureRandom    random          = new SecureRandom();
55         private MessageDigest   md;
56
57         public BaseArtifactMapper() throws ShibbolethConfigurationException {
58                 try {
59                         md = MessageDigest.getInstance("SHA-1");
60                 } catch (NoSuchAlgorithmException e) {
61                         log.error("No support found for SHA-1 digest algorithm: " + e);
62                         throw new ShibbolethConfigurationException(
63                                         "The IdP Artifact Mapper requires JCE support for the SHA-1 digest algorithm.");
64                 }
65
66         }
67
68         public ArtifactMapping recoverAssertion(String artifact) {
69
70                 try {
71                         //Decode the artifact
72                         byte[] decoded = new BASE64Decoder().decodeBuffer(artifact);
73                         if (decoded.length != 42) {
74                                 log.error("Invalid artifact length.");
75                                 return null;
76                         }
77
78                         //Check the type
79                         if (decoded[0] != typeCode[0] || decoded[1] != typeCode[1]) {
80                                 log.error("Incorrect artifact type code.");
81                                 return null;
82                         }
83
84                         //Grab the assertion handle
85                         byte[] assertionHandle = new byte[20];
86                         for (int assertionHandleCount = 0, decodedCount = 22; assertionHandleCount < assertionHandle.length; assertionHandleCount++, decodedCount++) {
87                                 assertionHandle[assertionHandleCount] = decoded[decodedCount];
88                         }
89                         String stringHandle = new String(assertionHandle);
90
91                         //delegate recovery to extenders
92                         return recoverAssertionImpl(stringHandle);
93
94                 } catch (IOException e) {
95                         log.error("Artifact not properly Base64 encoded.");
96                         return null;
97                 }
98         }
99
100         public String generateArtifact(SAMLAssertion assertion, HSRelyingParty relyingParty) {
101
102                 byte[] allArtifactComponents = new byte[42];
103
104                 // Add typecode
105                 allArtifactComponents[0] = typeCode[0];
106                 allArtifactComponents[1] = typeCode[1];
107
108                 // Add SourceID
109                 byte[] sourceID = new byte[20];
110                 synchronized (md) {
111                         sourceID = md.digest(relyingParty.getIdentityProvider().getProviderId().getBytes());
112                 }
113                 for (int sourceIdCount = 0, allComponentCount = 2; sourceIdCount < sourceID.length; sourceIdCount++, allComponentCount++) {
114                         allArtifactComponents[allComponentCount] = sourceID[sourceIdCount];
115                 }
116
117                 // Add Asserton Handle
118                 byte[] buffer = new byte[20];
119                 random.nextBytes(buffer);
120                 for (int assertionHandleCount = 0, allComponentCount = 22; assertionHandleCount < buffer.length; assertionHandleCount++, allComponentCount++) {
121                         allArtifactComponents[allComponentCount] = buffer[assertionHandleCount];
122                 }
123
124                 // Cache the assertion handle
125                 String assertionHandle = new String(buffer);
126
127                 // Delegate adding to extenders
128                 addAssertionImpl(assertionHandle, new ArtifactMapping(assertionHandle, assertion, relyingParty));
129
130                 // Return the encoded artifact
131                 return new BASE64Encoder().encode(allArtifactComponents);
132         }
133
134         /**
135          * Subclasses should implement artifact storage with this method.
136          */
137         protected abstract void addAssertionImpl(String assertionHandle, ArtifactMapping mapping);
138
139         /**
140          * Subclasses should implement artifact lookup with this method.
141          * 
142          * @param stringHandle
143          *            the artifact string
144          */
145         protected abstract ArtifactMapping recoverAssertionImpl(String artifact);
146
147 }