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