1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.security.util;
17
18 import java.io.IOException;
19 import java.net.URL;
20 import java.security.KeyStore;
21 import java.security.KeyStoreException;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.PrivateKey;
24 import java.security.PublicKey;
25 import java.security.UnrecoverableKeyException;
26 import java.security.cert.CertificateException;
27 import java.security.cert.X509Certificate;
28 import java.util.Arrays;
29 import java.util.Date;
30 import java.util.Map;
31
32 import javax.xml.parsers.DocumentBuilder;
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.ParserConfigurationException;
35 import javax.xml.transform.TransformerException;
36
37 import org.apache.xml.security.exceptions.XMLSecurityException;
38 import org.apache.xml.security.keys.KeyInfo;
39 import org.apache.xml.security.signature.XMLSignature;
40 import org.apache.xml.security.signature.XMLSignatureException;
41 import org.apache.xml.security.transforms.Transforms;
42 import org.apache.xml.security.utils.Constants;
43 import org.apache.xpath.XPathAPI;
44 import org.opensaml.SAMLAssertion;
45 import org.opensaml.SAMLAttribute;
46 import org.opensaml.SAMLAttributeStatement;
47 import org.opensaml.SAMLAuthenticationStatement;
48 import org.opensaml.SAMLException;
49 import org.opensaml.SAMLNameIdentifier;
50 import org.opensaml.SAMLSubject;
51 import org.w3c.dom.DOMException;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54 import org.w3c.dom.Node;
55 import org.w3c.dom.NodeList;
56
57
58
59
60
61
62
63 public class SamlUtils {
64
65 static {
66 org.apache.xml.security.Init.init();
67 }
68
69
70 private static String keystoreType;
71 private static String keystoreFile;
72 private static String keystorePass;
73 private static String privateKeyAlias;
74 private static String privateKeyPass;
75 private static String certificateAlias;
76
77 private static ThreadLocal<Map<String,String>> samlPropertiesHolder = new ThreadLocal<Map<String,String>>();
78
79 public static SAMLAssertion createAssertion() throws SAMLException, CloneNotSupportedException{
80
81 String user = getSamlProperties().get("user");
82 String pgt = getSamlProperties().get("proxyGrantingTicket");
83 String proxies = getSamlProperties().get("proxies");
84 String issuer = getSamlProperties().get("samlIssuerForUser");
85 String nameQualifier = getSamlProperties().get("samlIssuerForUser");
86
87 SAMLAssertion assertion = new SAMLAssertion();
88 assertion.setIssuer(issuer);
89
90
91 SAMLNameIdentifier nameId = new SAMLNameIdentifier(user, nameQualifier, "");
92 String[] confirmationMethods = {SAMLSubject.CONF_SENDER_VOUCHES};
93 SAMLSubject subject = new SAMLSubject();
94 subject.setNameIdentifier(nameId);
95 subject.setConfirmationMethods(Arrays.asList(confirmationMethods));
96
97
98 SAMLAuthenticationStatement authStmt = new SAMLAuthenticationStatement();
99 authStmt.setAuthInstant(new Date());
100 authStmt.setAuthMethod(SAMLAuthenticationStatement.AuthenticationMethod_Password);
101 authStmt.setSubject(subject);
102
103
104 SAMLAttributeStatement attrStatement = new SAMLAttributeStatement();
105 SAMLAttribute attr1 = new SAMLAttribute();
106 attr1.setName("proxyGrantingTicket");
107 attr1.setNamespace("http://student.kuali.org/wsdl/security/saml");
108
109 SAMLAttribute attr2 = new SAMLAttribute();
110 attr2.setName("proxies");
111 attr2.setNamespace("http://student.kuali.org/wsdl/security/saml");
112
113 attr1.addValue(pgt);
114 attr2.addValue(proxies);
115
116 attrStatement.addAttribute(attr1);
117 attrStatement.addAttribute(attr2);
118
119 SAMLSubject subjectInAttr = (SAMLSubject)subject.clone();
120 attrStatement.setSubject(subjectInAttr);
121
122
123 assertion.addStatement(authStmt);
124 assertion.addStatement(attrStatement);
125
126 return assertion;
127 }
128
129 public static void setSamlProperties(Map<String, String> samlProperties){
130
131 SamlUtils.samlPropertiesHolder.set(samlProperties);
132 }
133
134 public static Map<String, String> getSamlProperties() {
135
136 return SamlUtils.samlPropertiesHolder.get();
137 }
138
139 public static Document signAssertion(SAMLAssertion assertion) throws XMLSecurityException, KeyStoreException,
140 NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException,
141 ParserConfigurationException, DOMException, SAMLException {
142 Constants.setSignatureSpecNSprefix("ds");
143
144 ClassLoader classLoader = SamlUtils.class.getClassLoader();
145 URL url = classLoader.getResource(keystoreFile);
146
147
148 KeyStore ks = KeyStore.getInstance(keystoreType);
149 ks.load(url.openStream(), keystorePass.toCharArray());
150
151
152 PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());
153
154 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
155
156
157 dbf.setNamespaceAware(true);
158
159 DocumentBuilder db = dbf.newDocumentBuilder();
160 Document doc = db.newDocument();
161
162 Element root = doc.createElementNS("http://student.kuali.org", "ks:KSSecureToken");
163 root.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:ks", "http://student.kuali.org");
164
165 doc.appendChild(root);
166
167 root.appendChild(assertion.toDOM(doc));
168
169 XMLSignature sig = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA);
170
171
172
173
174
175
176
177
178
179 root.appendChild(sig.getElement());
180
181
182 Transforms transforms = new Transforms(doc);
183
184
185
186 transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
187
188
189
190 transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
191
192 sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
193
194
195
196 X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);
197
198 sig.addKeyInfo(cert);
199 sig.addKeyInfo(cert.getPublicKey());
200
201 sig.sign(privateKey);
202
203 return doc;
204 }
205
206 public static SAMLAssertion unsignAssertion(Document doc) throws TransformerException, XMLSecurityException, SAMLException {
207 boolean validSig = false;
208 Element nscontext = doc.createElementNS(null, "namespaceContext");
209 nscontext.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:ds", Constants.SignatureSpecNS);
210
211 Element sigElement = (Element) XPathAPI.selectSingleNode(doc, "//ds:Signature[1]", nscontext);
212
213 XMLSignature signature = new XMLSignature(sigElement, null);
214
215 KeyInfo ki = signature.getKeyInfo();
216
217 if (ki != null) {
218 X509Certificate cert = ki.getX509Certificate();
219
220 if (cert != null) {
221 validSig = signature.checkSignatureValue(cert);
222
223 } else {
224 PublicKey pk = ki.getPublicKey();
225
226 if (pk != null) {
227 validSig = signature.checkSignatureValue(pk);
228
229 } else {
230 throw new XMLSignatureException("Could not find a certificate or a public key in the message, can't check the signature");
231 }
232 }
233 } else {
234 throw new XMLSignatureException("Could not find a KeyInfo element in message");
235 }
236
237
238 if(validSig){
239 NodeList nodeList = doc.getDocumentElement().getChildNodes();
240 Node childNode = null;
241
242 for(int i=0; i < nodeList.getLength(); i++){
243 childNode = nodeList.item(i);
244 if((childNode.getNodeName().equals("Assertion")) && (childNode.getNodeType() == Node.ELEMENT_NODE)){
245 SAMLAssertion assertion = new SAMLAssertion((Element)childNode);
246 return assertion;
247 }
248 }
249 }
250
251 throw new XMLSignatureException("The message signature was invalid");
252 }
253
254
255
256
257 public String getKeystoreType() {
258 return keystoreType;
259 }
260
261
262
263
264 public void setKeystoreType(String keystoreType) {
265 SamlUtils.keystoreType = keystoreType;
266 }
267
268
269
270
271 public String getKeystoreFile() {
272 return keystoreFile;
273 }
274
275
276
277
278 public void setKeystoreFile(String keystoreFile) {
279 SamlUtils.keystoreFile = keystoreFile;
280 }
281
282
283
284
285 public String getKeystorePass() {
286 return keystorePass;
287 }
288
289
290
291
292 public void setKeystorePass(String keystorePass) {
293 SamlUtils.keystorePass = keystorePass;
294 }
295
296
297
298
299 public String getPrivateKeyAlias() {
300 return privateKeyAlias;
301 }
302
303
304
305
306 public void setPrivateKeyAlias(String privateKeyAlias) {
307 SamlUtils.privateKeyAlias = privateKeyAlias;
308 }
309
310
311
312
313 public String getPrivateKeyPass() {
314 return privateKeyPass;
315 }
316
317
318
319
320 public void setPrivateKeyPass(String privateKeyPass) {
321 SamlUtils.privateKeyPass = privateKeyPass;
322 }
323
324
325
326
327 public String getCertificateAlias() {
328 return certificateAlias;
329 }
330
331
332
333
334 public void setCertificateAlias(String certificateAlias) {
335 SamlUtils.certificateAlias = certificateAlias;
336 }
337 }