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