1 package org.kuali.student.security.trust.service;
2
3 import java.io.BufferedReader;
4 import java.io.InputStreamReader;
5 import java.io.StringWriter;
6 import java.io.UnsupportedEncodingException;
7 import java.net.HttpURLConnection;
8 import java.net.URL;
9 import java.net.URLEncoder;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.jws.WebService;
15 import javax.xml.bind.JAXBElement;
16 import javax.xml.parsers.DocumentBuilder;
17 import javax.xml.parsers.DocumentBuilderFactory;
18 import javax.xml.transform.Transformer;
19 import javax.xml.transform.TransformerFactory;
20 import javax.xml.transform.dom.DOMSource;
21 import javax.xml.transform.stream.StreamResult;
22
23 import org.jasig.cas.client.util.CommonUtils;
24 import org.jasig.cas.client.util.XmlUtils;
25 import org.kuali.student.security.exceptions.KSSecurityException;
26 import org.kuali.student.security.trust.dto.RequestSecurityTokenResponseCollectionType;
27 import org.kuali.student.security.trust.dto.RequestSecurityTokenResponseType;
28 import org.kuali.student.security.trust.dto.RequestSecurityTokenType;
29 import org.kuali.student.security.util.SamlUtils;
30 import org.opensaml.SAMLAssertion;
31 import org.w3c.dom.Document;
32 import org.w3c.dom.Element;
33 import org.w3c.dom.Node;
34
35
36
37
38
39
40
41
42 @WebService(endpointInterface = "org.kuali.student.security.trust.service.SecurityTokenService", serviceName = "SecurityTokenService",
43 portName = "SecurityTokenService", targetNamespace = "http://schemas.xmlsoap.org/ws/2005/02/trust/wsdl")
44 public class SecurityTokenServiceImpl implements SecurityTokenService {
45
46 public static final String WST_NS_05_02 = "http://schemas.xmlsoap.org/ws/2005/02/trust";
47 public static final String SAML_11_NS = "urn:oasis:names:tc:SAML:1.0:assertion";
48
49
50 private String casServerUrl;
51 private String samlIssuerForUser;
52 private String proxyCallBackUrl;
53
54 public RequestSecurityTokenResponseCollectionType requestSecurityToken2(RequestSecurityTokenType request) throws KSSecurityException
55 {
56 return null;
57 }
58
59 public RequestSecurityTokenResponseType requestSecurityToken(RequestSecurityTokenType request) throws KSSecurityException
60 {
61
62 String context = request.getContext();
63 List<Object> objects = request.getAny();
64
65 String tokenTypeUri = null;
66 String requestTypeUri = null;
67 String proxyTicketId = null;
68 String proxyTargetService = null;
69
70 for(Object o : objects){
71
72 if(o instanceof JAXBElement){
73 JAXBElement<?> e = (JAXBElement<?>)o;
74 if( e.getName().getLocalPart().equalsIgnoreCase("TokenType")){
75 tokenTypeUri = (String)e.getValue();
76 }
77 else if(e.getName().getLocalPart().equalsIgnoreCase("RequestType")) {
78 requestTypeUri = (String)e.getValue();
79 }
80 else if(e.getName().getLocalPart().equalsIgnoreCase("CasProxyTicket")) {
81 proxyTicketId = (String)e.getValue();
82 }
83 else if(e.getName().getLocalPart().equalsIgnoreCase("CasProxyTargetService")) {
84 proxyTargetService = (String)e.getValue();
85 }
86
87
88 } else if(o instanceof Element){
89 Element e = (Element)o;
90 if( e.getLocalName().equalsIgnoreCase("TokenType")){
91 tokenTypeUri = e.getTextContent();
92 }
93 else if(e.getLocalName().equalsIgnoreCase("RequestType")) {
94 requestTypeUri = e.getTextContent();
95 }
96 else if(e.getLocalName().equalsIgnoreCase("CasProxyTicket")) {
97 proxyTicketId = e.getTextContent();
98 }
99 else if(e.getLocalName().equalsIgnoreCase("CasProxyTargetService")) {
100 proxyTargetService = e.getTextContent();
101 }
102 }
103 }
104
105
106
107 RequestSecurityTokenResponseType rstr = new RequestSecurityTokenResponseType();
108
109 if(requestTypeUri == null){
110 throw new KSSecurityException("The element RequestType is required");
111 }
112 if(proxyTicketId == null || proxyTargetService == null){
113 throw new KSSecurityException("The elements CasProxyTicket and CasProxyTargetService are required");
114 }
115
116
117
118 if(context != null){
119 rstr.setContext(context);
120 }
121
122 if(tokenTypeUri == null){
123
124 tokenTypeUri = SAML_11_NS;
125 }
126
127
128 if(tokenTypeUri.equals(SAML_11_NS) && requestTypeUri.endsWith("/Issue") ){
129
130 Element tokenType = null;
131 Element requestedSecurityToken = null;
132 Document signedSAMLDoc = null;
133 try{
134
135 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
136
137
138 dbf.setNamespaceAware(true);
139
140 DocumentBuilder db = dbf.newDocumentBuilder();
141 Document doc = db.newDocument();
142
143 tokenType = doc.createElementNS(WST_NS_05_02, "TokenType");
144 tokenType.setTextContent(tokenTypeUri);
145
146 requestedSecurityToken = doc.createElementNS(WST_NS_05_02, "RequestedSecurityToken");
147
148 String testProperty = System.getProperty("ks.test.securityTokenService.useCas", "true");
149
150 if(Boolean.valueOf(testProperty)){
151 signedSAMLDoc = validateCasProxyTicket(proxyTicketId, proxyTargetService);
152 } else {
153
154 signedSAMLDoc = getSamlPrincipal("WS Trust Service is in test mode");
155 }
156 Node signedSAMLAssertion = signedSAMLDoc.getDocumentElement();
157 requestedSecurityToken.appendChild(doc.importNode(signedSAMLAssertion, true));
158
159 } catch(Exception e){
160 throw new KSSecurityException(e);
161 }
162 rstr.getAny().add(tokenType);
163 rstr.getAny().add(requestedSecurityToken);
164 }
165
166 return rstr;
167 }
168
169 private Document validateCasProxyTicket(String proxyTicketId, String proxyTargetService) throws KSSecurityException{
170
171 String url = constructUrl(proxyTicketId, proxyTargetService);
172 HttpURLConnection conn = null;
173
174 try {
175 URL constructedUrl = new URL(url);
176 conn = (HttpURLConnection) constructedUrl.openConnection();
177
178 BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
179
180 String line;
181 StringBuffer stringBuffer = new StringBuffer(255);
182 String response;
183
184 while ((line = in.readLine()) != null) {
185 stringBuffer.append(line);
186 }
187
188 response = stringBuffer.toString();
189 String error = XmlUtils.getTextForElement(response, "authenticationFailure");
190
191 if (CommonUtils.isNotEmpty(error)) {
192
193 throw new KSSecurityException(error);
194 }
195
196 String user = XmlUtils.getTextForElement(response, "user");
197 String pgt = XmlUtils.getTextForElement(response, "proxyGrantingTicket");
198 String proxies = XmlUtils.getTextForElement(response, "proxies");
199
200 Map<String,String> samlProperties = new HashMap<String,String>();
201 samlProperties.put("user", user.trim());
202 samlProperties.put("proxyGrantingTicket", pgt.trim());
203 samlProperties.put("proxies", proxies.trim());
204 samlProperties.put("samlIssuerForUser", samlIssuerForUser.trim());
205
206 SamlUtils.setSamlProperties(samlProperties);
207 SAMLAssertion samlAssertion = SamlUtils.createAssertion();
208
209 Document signedSAML = SamlUtils.signAssertion(samlAssertion);
210 return signedSAML;
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 } catch (final Exception e) {
228 throw new KSSecurityException(e);
229 } finally {
230 if (conn != null) {
231 conn.disconnect();
232 }
233 }
234 }
235
236 private String constructUrl(String proxyTicketId, String proxyTargetService) throws KSSecurityException{
237 try {
238 return this.casServerUrl + (this.casServerUrl.endsWith("/") ? "" : "/") + "proxyValidate" + "?ticket="
239 + proxyTicketId + "&service=" + URLEncoder.encode(proxyTargetService, "UTF-8")
240 + "&pgtUrl=" + URLEncoder.encode(proxyCallBackUrl, "UTF-8");
241 } catch (UnsupportedEncodingException e) {
242 throw new KSSecurityException(e);
243 }
244 }
245
246 private Document getSamlPrincipal(String principal) throws KSSecurityException{
247 try {
248 Map<String,String> samlProperties = new HashMap<String,String>();
249 samlProperties.put("user", principal);
250 samlProperties.put("proxyGrantingTicket", "");
251 samlProperties.put("proxies", "");
252 if(samlIssuerForUser == null){
253 samlProperties.put("samlIssuerForUser", "org.kuali.student.trust.sts");
254 }else{
255 samlProperties.put("samlIssuerForUser", samlIssuerForUser.trim());
256 }
257
258 SamlUtils.setSamlProperties(samlProperties);
259 SAMLAssertion samlAssertion = SamlUtils.createAssertion();
260
261 Document signedSAML = SamlUtils.signAssertion(samlAssertion);
262
263 return signedSAML;
264
265 } catch (final Exception e) {
266 throw new KSSecurityException(e);
267 }
268
269 }
270
271 public String getCasServerUrl() {
272 return casServerUrl;
273 }
274
275 public void setCasServerUrl(String casServerUrl) {
276 this.casServerUrl = casServerUrl;
277 }
278
279 public String getSamlIssuerForUser() {
280 return samlIssuerForUser;
281 }
282
283 public void setSamlIssuerForUser(String samlIssuerForUser) {
284 this.samlIssuerForUser = samlIssuerForUser;
285 }
286
287 public String getProxyCallBackUrl() {
288 return proxyCallBackUrl;
289 }
290
291 public void setProxyCallBackUrl(String proxyCallBackUrl) {
292 this.proxyCallBackUrl = proxyCallBackUrl;
293 }
294 }