View Javadoc

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   * This class was generated by Apache CXF 2.2.8
37   * Thu Jun 03 14:08:34 EDT 2010
38   * Generated source version: 2.2.8
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          // Parse the request
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              // if its being accessed as a SOAP service with JAXB.
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              // if its being accessed with a client impl, no SOAP.
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         // Create the Response
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         //This optional URI specifies the identifier from the original request.
117        // That is, if a context URI is specified on a RST, then it MUST be echoed on the corresponding RSTRs.
118         if(context != null){
119             rstr.setContext(context);
120         }
121         
122         if(tokenTypeUri == null){
123             //default to SAML
124             tokenTypeUri = SAML_11_NS;
125         }
126        
127         // We are just handling request for tokens of type SAML and for new token issuing, so this is just one BAD mother IF.
128         if(tokenTypeUri.equals(SAML_11_NS) && requestTypeUri.endsWith("/Issue") ){
129             // create the TokenType and RequestedSecurityToken Elements
130             Element tokenType = null;
131             Element requestedSecurityToken = null;
132             Document signedSAMLDoc = null;
133             try{
134                 
135                 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
136         
137                 //XML Signature needs to be namespace aware -- not sure if I need this here
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                     // Create TEST SAML
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                 //return error;
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             // transform the saml DOM into a writer, and return as a string response
213             /*DOMSource domSource = new DOMSource(signedSAML);
214             StringWriter writer = new StringWriter();
215             StreamResult result = new StreamResult(writer);
216             
217             TransformerFactory tf = TransformerFactory.newInstance();
218             Transformer transformer;
219             
220             transformer = tf.newTransformer();
221             transformer.transform(domSource, result);
222             
223             writer.flush();
224             
225             return writer.toString();*/
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 }