1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.dataConnector;
18
19 import java.security.MessageDigest;
20 import java.security.NoSuchAlgorithmException;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Map;
24
25 import org.opensaml.xml.util.Base64;
26 import org.opensaml.xml.util.DatatypeHelper;
27 import org.opensaml.xml.util.LazyMap;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
32 import edu.internet2.middleware.shibboleth.common.attribute.provider.BasicAttribute;
33 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
34 import edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.ShibbolethResolutionContext;
35
36
37
38
39
40
41
42 public class ComputedIDDataConnector extends BaseDataConnector {
43
44
45 private final Logger log = LoggerFactory.getLogger(ComputedIDDataConnector.class);
46
47
48 private String generatedAttribute;
49
50
51 private String sourceAttribute;
52
53
54 private byte[] salt;
55
56
57
58
59
60
61
62
63 public ComputedIDDataConnector(String generatedAttributeId, String sourceAttributeId, byte[] idSalt) {
64 log.warn("This data connector is deprecated. The StoredID data connector should be used in its place.");
65
66 if (DatatypeHelper.isEmpty(generatedAttributeId)) {
67 throw new IllegalArgumentException("Provided generated attribute ID must not be empty");
68 }
69 generatedAttribute = generatedAttributeId;
70
71 if (DatatypeHelper.isEmpty(sourceAttributeId)) {
72 throw new IllegalArgumentException("Provided source attribute ID must not be empty");
73 }
74 sourceAttribute = sourceAttributeId;
75
76 if (idSalt.length < 16) {
77 throw new IllegalArgumentException("Provided salt must be at least 16 bytes in size.");
78 }
79 salt = idSalt;
80 }
81
82
83
84
85
86
87 public byte[] getSalt() {
88 return salt;
89 }
90
91
92
93
94
95
96 public String getSourceAttributeId() {
97 return sourceAttribute;
98 }
99
100
101
102
103
104
105 public String getGeneratedAttributeId() {
106 return generatedAttribute;
107 }
108
109
110 public Map<String, BaseAttribute> resolve(ShibbolethResolutionContext resolutionContext)
111 throws AttributeResolutionException {
112
113 String inboundMessageIssuer = resolutionContext.getAttributeRequestContext().getInboundMessageIssuer();
114 if (inboundMessageIssuer == null) {
115 log.debug("No inbound message issuer identified, unable to compute ID");
116 throw new AttributeResolutionException("No inbound message issuer identified");
117 }
118
119 Collection<Object> sourceIdValues = getValuesFromAllDependencies(resolutionContext, getSourceAttributeId());
120 if (sourceIdValues == null || sourceIdValues.isEmpty()) {
121 log.debug("Source attribute {} for connector {} provide no values", getSourceAttributeId(), getId());
122 return Collections.EMPTY_MAP;
123 }
124
125 if (sourceIdValues.size() > 1) {
126 log.warn("Source attribute {} for connector {} has more than one value, only the first value is used",
127 getSourceAttributeId(), getId());
128 }
129 String sourceId = sourceIdValues.iterator().next().toString();
130
131 BasicAttribute<String> computedIdAttrib = new BasicAttribute<String>();
132 computedIdAttrib.setId(getGeneratedAttributeId());
133
134 try {
135 MessageDigest md = MessageDigest.getInstance("SHA");
136 md.update(inboundMessageIssuer.getBytes());
137 md.update((byte) '!');
138 md.update(sourceId.getBytes());
139 md.update((byte) '!');
140
141 computedIdAttrib.getValues().add(Base64.encodeBytes(md.digest(salt)));
142
143 LazyMap<String, BaseAttribute> attribtues = new LazyMap<String, BaseAttribute>();
144 attribtues.put(getGeneratedAttributeId(), computedIdAttrib);
145 return attribtues;
146 } catch (NoSuchAlgorithmException e) {
147 log.error("JVM error, SHA-1 hash is not supported.");
148 throw new AttributeResolutionException("SHA-1A is not supported, unable to compute ID");
149 }
150 }
151
152
153 public void validate() throws AttributeResolutionException {
154 if (getDependencyIds() == null || getDependencyIds().size() != 1) {
155 log.error("Computed ID " + getId() + " data connectore requires exactly one dependency");
156 throw new AttributeResolutionException("Computed ID " + getId()
157 + " data connectore requires exactly one dependency");
158 }
159 }
160 }