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.Map;
23
24 import org.opensaml.xml.util.Base64;
25 import org.opensaml.xml.util.DatatypeHelper;
26 import org.opensaml.xml.util.LazyMap;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
31 import edu.internet2.middleware.shibboleth.common.attribute.provider.BasicAttribute;
32 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
33 import edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.ShibbolethResolutionContext;
34
35
36
37
38
39
40
41 public class ComputedIDDataConnector extends BaseDataConnector {
42
43
44 private final Logger log = LoggerFactory.getLogger(ComputedIDDataConnector.class);
45
46
47 private String generatedAttribute;
48
49
50 private String sourceAttribute;
51
52
53 private byte[] salt;
54
55
56
57
58
59
60
61
62 public ComputedIDDataConnector(String generatedAttributeId, String sourceAttributeId, byte[] idSalt) {
63 log.warn("This data connector is deprecated. The StoredID data connector should be used in its place.");
64
65 if (DatatypeHelper.isEmpty(generatedAttributeId)) {
66 throw new IllegalArgumentException("Provided generated attribute ID must not be empty");
67 }
68 generatedAttribute = generatedAttributeId;
69
70 if (DatatypeHelper.isEmpty(sourceAttributeId)) {
71 throw new IllegalArgumentException("Provided source attribute ID must not be empty");
72 }
73 sourceAttribute = sourceAttributeId;
74
75 if (idSalt.length < 16) {
76 throw new IllegalArgumentException("Provided salt must be at least 16 bytes in size.");
77 }
78 salt = idSalt;
79 }
80
81
82
83
84
85
86 public byte[] getSalt() {
87 return salt;
88 }
89
90
91
92
93
94
95 public String getSourceAttributeId() {
96 return sourceAttribute;
97 }
98
99
100
101
102
103
104 public String getGeneratedAttributeId() {
105 return generatedAttribute;
106 }
107
108
109 public Map<String, BaseAttribute> resolve(ShibbolethResolutionContext resolutionContext)
110 throws AttributeResolutionException {
111
112 String inboundMessageIssuer = resolutionContext.getAttributeRequestContext().getInboundMessageIssuer();
113 if (inboundMessageIssuer == null) {
114 log.error("No inbound message issuer identified, unable to compute ID");
115 throw new AttributeResolutionException("No inbound message issuer identified");
116 }
117
118 Collection<Object> sourceIdValues = getValuesFromAllDependencies(resolutionContext, getSourceAttributeId());
119 if (sourceIdValues == null || sourceIdValues.isEmpty()) {
120 log.error("Source attribute {} for connector {} provide no values", getSourceAttributeId(), getId());
121 throw new AttributeResolutionException("Source attribute " + getSourceAttributeId() + " for connector "
122 + getId() + " provided no values");
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 }