Coverage Report - org.kuali.student.security.util.SamlUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
SamlUtils
0%
0/106
0%
0/14
1.647
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the
 3  
  * Educational Community License, Version 2.0 (the "License"); you may
 4  
  * not use this file except in compliance with the License. You may
 5  
  * obtain a copy of the License at
 6  
  *
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing,
 10  
  * software distributed under the License is distributed on an "AS IS"
 11  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 12  
  * or implied. See the License for the specific language governing
 13  
  * permissions and limitations under the License.
 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  
  * This is a description of what this class does - Rich don't forget to fill this in. 
 59  
  * 
 60  
  * @author Kuali Rice Team (kuali-rice@googlegroups.com)
 61  
  *
 62  
  */
 63  0
 public class SamlUtils {
 64  
 
 65  
     static {
 66  0
         org.apache.xml.security.Init.init();
 67  
      }
 68  
     
 69  
     //All the parameters for the keystore
 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  0
     private static ThreadLocal<Map<String,String>> samlPropertiesHolder = new ThreadLocal<Map<String,String>>();
 78  
     
 79  
     public static SAMLAssertion createAssertion() throws SAMLException, CloneNotSupportedException{
 80  
         
 81  0
         String user = getSamlProperties().get("user");
 82  0
         String pgt = getSamlProperties().get("proxyGrantingTicket");
 83  0
         String proxies = getSamlProperties().get("proxies");
 84  0
         String issuer = getSamlProperties().get("samlIssuerForUser");
 85  0
         String nameQualifier = getSamlProperties().get("samlIssuerForUser");
 86  
         
 87  0
         SAMLAssertion assertion = new SAMLAssertion();
 88  0
         assertion.setIssuer(issuer);
 89  
         
 90  
         // prepare subject
 91  0
         SAMLNameIdentifier nameId = new SAMLNameIdentifier(user, nameQualifier, "");
 92  0
         String[] confirmationMethods = {SAMLSubject.CONF_SENDER_VOUCHES};
 93  0
         SAMLSubject subject = new SAMLSubject();
 94  0
         subject.setNameIdentifier(nameId);
 95  0
         subject.setConfirmationMethods(Arrays.asList(confirmationMethods));
 96  
     
 97  
         // prepare auth statement
 98  0
         SAMLAuthenticationStatement authStmt = new SAMLAuthenticationStatement();
 99  0
         authStmt.setAuthInstant(new Date());
 100  0
         authStmt.setAuthMethod(SAMLAuthenticationStatement.AuthenticationMethod_Password);
 101  0
         authStmt.setSubject(subject);
 102  
     
 103  
         // prepare attributes
 104  0
         SAMLAttributeStatement attrStatement = new SAMLAttributeStatement();
 105  0
         SAMLAttribute attr1 = new SAMLAttribute();
 106  0
         attr1.setName("proxyGrantingTicket");
 107  0
         attr1.setNamespace("http://student.kuali.org/wsdl/security/saml");
 108  
     
 109  0
         SAMLAttribute attr2 = new SAMLAttribute();
 110  0
         attr2.setName("proxies");
 111  0
         attr2.setNamespace("http://student.kuali.org/wsdl/security/saml");
 112  
     
 113  0
         attr1.addValue(pgt);
 114  0
         attr2.addValue(proxies);
 115  
         
 116  0
         attrStatement.addAttribute(attr1);
 117  0
         attrStatement.addAttribute(attr2);
 118  
         
 119  0
         SAMLSubject subjectInAttr = (SAMLSubject)subject.clone();
 120  0
         attrStatement.setSubject(subjectInAttr);
 121  
         
 122  
         // prepare Assertion
 123  0
         assertion.addStatement(authStmt);
 124  0
         assertion.addStatement(attrStatement);
 125  
         
 126  0
         return assertion;    
 127  
     }
 128  
     
 129  
     public static void setSamlProperties(Map<String, String> samlProperties){
 130  
         //this.samlProperties = samlProperties;
 131  0
         SamlUtils.samlPropertiesHolder.set(samlProperties);
 132  0
     }
 133  
 
 134  
     public static Map<String, String> getSamlProperties() {
 135  
         //return samlProperties;
 136  0
         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  0
         Constants.setSignatureSpecNSprefix("ds");
 143  
         
 144  0
         ClassLoader classLoader = SamlUtils.class.getClassLoader();
 145  0
         URL url = classLoader.getResource(keystoreFile);
 146  
 
 147  
         //load the keystore
 148  0
         KeyStore ks = KeyStore.getInstance(keystoreType);
 149  0
         ks.load(url.openStream(), keystorePass.toCharArray());
 150  
 
 151  
         //get the private key for signing.
 152  0
         PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());
 153  
         
 154  0
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 155  
 
 156  
         //XML Signature needs to be namespace aware
 157  0
         dbf.setNamespaceAware(true);
 158  
 
 159  0
         DocumentBuilder db = dbf.newDocumentBuilder();
 160  0
         Document doc = db.newDocument();
 161  
 
 162  0
         Element root = doc.createElementNS("http://student.kuali.org", "ks:KSSecureToken");
 163  0
         root.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:ks", "http://student.kuali.org");
 164  
         
 165  0
         doc.appendChild(root);
 166  
         // append the SAML assertion to the root.
 167  0
         root.appendChild(assertion.toDOM(doc));
 168  
         
 169  0
         XMLSignature sig = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA);
 170  
                                                         //XMLSignature.ALGO_ID_SIGNATURE_DSA);
 171  
 
 172  
         //Append the signature element to the root element before signing because
 173  
         //this is going to be an enveloped signature.
 174  
         //This means the signature is going to be enveloped by the document.
 175  
         //Two other possible forms are enveloping where the document is inside the
 176  
         //signature and detached where they are seperate.
 177  
         //Note that they can be mixed in 1 signature with seperate references as
 178  
         //shown below.
 179  0
         root.appendChild(sig.getElement());
 180  
         
 181  
         //create the transforms object for the Document/Reference
 182  0
         Transforms transforms = new Transforms(doc);
 183  
 
 184  
         //First we have to strip away the signature element (it's not part of the
 185  
         //signature calculations). The enveloped transform can be used for this.
 186  0
         transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
 187  
         //Part of the signature element needs to be canonicalized. It is a kind
 188  
         //of normalizing algorithm for XML. For more information please take a
 189  
         //look at the W3C XML Digital Signature webpage.
 190  0
         transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
 191  
         //Add the above Document/Reference
 192  0
         sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
 193  
         
 194  
 
 195  
         //Add in the KeyInfo for the certificate that we used the private key of
 196  0
         X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);
 197  
 
 198  0
         sig.addKeyInfo(cert);
 199  0
         sig.addKeyInfo(cert.getPublicKey());
 200  
         // Sign the document
 201  0
         sig.sign(privateKey);
 202  
         
 203  0
         return doc;
 204  
     }
 205  
 
 206  
     public static SAMLAssertion unsignAssertion(Document doc) throws TransformerException, XMLSecurityException, SAMLException {
 207  0
         boolean validSig = false;
 208  0
         Element nscontext = doc.createElementNS(null, "namespaceContext");
 209  0
         nscontext.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:ds", Constants.SignatureSpecNS);
 210  
         
 211  0
         Element sigElement = (Element) XPathAPI.selectSingleNode(doc, "//ds:Signature[1]", nscontext);
 212  
         
 213  0
         XMLSignature signature = new XMLSignature(sigElement, null);
 214  
         
 215  0
         KeyInfo ki = signature.getKeyInfo();
 216  
         
 217  0
         if (ki != null) {
 218  0
            X509Certificate cert = ki.getX509Certificate();
 219  
 
 220  0
            if (cert != null) {
 221  0
                validSig = signature.checkSignatureValue(cert);
 222  
               
 223  
            } else {
 224  0
               PublicKey pk = ki.getPublicKey();
 225  
 
 226  0
               if (pk != null) {
 227  0
                  validSig = signature.checkSignatureValue(pk);
 228  
                  
 229  
               } else {
 230  0
                  throw new XMLSignatureException("Could not find a certificate or a public key in the message, can't check the signature");
 231  
               }
 232  
            }
 233  0
         } else {
 234  0
            throw new XMLSignatureException("Could not find a KeyInfo element in message");
 235  
         }
 236  
         
 237  
         // if the signature is valid get the assertion and return it.
 238  0
         if(validSig){
 239  0
             NodeList nodeList = doc.getDocumentElement().getChildNodes();
 240  0
             Node childNode = null;
 241  
             
 242  0
             for(int i=0; i < nodeList.getLength(); i++){
 243  0
                 childNode = nodeList.item(i);
 244  0
                 if((childNode.getNodeName().equals("Assertion")) && (childNode.getNodeType() == Node.ELEMENT_NODE)){
 245  0
                     SAMLAssertion assertion = new SAMLAssertion((Element)childNode);
 246  0
                     return assertion;
 247  
                 }
 248  
             }
 249  
         }
 250  
         
 251  0
         throw new XMLSignatureException("The message signature was invalid");
 252  
     }
 253  
     
 254  
     /**
 255  
      * @return the keystoreType
 256  
      */
 257  
     public String getKeystoreType() {
 258  0
         return keystoreType;
 259  
     }
 260  
 
 261  
     /**
 262  
      * @param keystoreType the keystoreType to set
 263  
      */
 264  
     public void setKeystoreType(String keystoreType) {
 265  0
         SamlUtils.keystoreType = keystoreType;
 266  0
     }
 267  
 
 268  
     /**
 269  
      * @return the keystoreFile
 270  
      */
 271  
     public String getKeystoreFile() {
 272  0
         return keystoreFile;
 273  
     }
 274  
 
 275  
     /**
 276  
      * @param keystoreFile the keystoreFile to set
 277  
      */
 278  
     public void setKeystoreFile(String keystoreFile) {
 279  0
         SamlUtils.keystoreFile = keystoreFile;
 280  0
     }
 281  
 
 282  
     /**
 283  
      * @return the keystorePass
 284  
      */
 285  
     public String getKeystorePass() {
 286  0
         return keystorePass;
 287  
     }
 288  
 
 289  
     /**
 290  
      * @param keystorePass the keystorePass to set
 291  
      */
 292  
     public void setKeystorePass(String keystorePass) {
 293  0
         SamlUtils.keystorePass = keystorePass;
 294  0
     }
 295  
 
 296  
     /**
 297  
      * @return the privateKeyAlias
 298  
      */
 299  
     public String getPrivateKeyAlias() {
 300  0
         return privateKeyAlias;
 301  
     }
 302  
 
 303  
     /**
 304  
      * @param privateKeyAlias the privateKeyAlias to set
 305  
      */
 306  
     public void setPrivateKeyAlias(String privateKeyAlias) {
 307  0
         SamlUtils.privateKeyAlias = privateKeyAlias;
 308  0
     }
 309  
 
 310  
     /**
 311  
      * @return the privateKeyPass
 312  
      */
 313  
     public String getPrivateKeyPass() {
 314  0
         return privateKeyPass;
 315  
     }
 316  
 
 317  
     /**
 318  
      * @param privateKeyPass the privateKeyPass to set
 319  
      */
 320  
     public void setPrivateKeyPass(String privateKeyPass) {
 321  0
         SamlUtils.privateKeyPass = privateKeyPass;
 322  0
     }
 323  
 
 324  
     /**
 325  
      * @return the certificateAlias
 326  
      */
 327  
     public String getCertificateAlias() {
 328  0
         return certificateAlias;
 329  
     }
 330  
 
 331  
     /**
 332  
      * @param certificateAlias the certificateAlias to set
 333  
      */
 334  
     public void setCertificateAlias(String certificateAlias) {
 335  0
         SamlUtils.certificateAlias = certificateAlias;
 336  0
     }
 337  
 }