/** * Returns SAMLv2 <code>Response</code>. SAMLv2 request is sent enclosed in the body of a SOAP * Message to a SOAP endpoint. Prior to sending the request query, attributes required for * completeness of the SAMLv2 Request will be set (eg. Issuer) if not already set. Message will be * signed if signing is enabled. SAMLv2 Query Request will be enclosed in the SOAP Body to create * a SOAP message to send to the server. * * @param request the SAMLv2 <code>RequestAbstract</code> object. * @param pepEntityID entity identifier of the hosted query requester. * @param pdpEntityID entity identifier of the remote server. * @return SAMLv2 <code>Response</code> received from the Query Responder. * @throws SAML2Exception if there is an error processing the query. */ public static Response processXACMLQuery( RequestAbstract request, String pepEntityID, String pdpEntityID) throws SAML2Exception { String classMethod = "QueryClient:processXACMLQuery"; String realm = "/"; Response samlResponse = null; Response response = null; // retreive pepEntityID metadata if (pepEntityID == null || pepEntityID.length() == 0) { debug.error(classMethod + "PEP Identifier is null"); String[] data = {pepEntityID}; LogUtil.error(Level.INFO, LogUtil.INVALID_PEP_ID, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("nullPEP")); } // retreive pdpEntityID metadata if (pdpEntityID == null || pdpEntityID.length() == 0) { debug.error(classMethod + "PDP Identifier is null"); String[] data = {pdpEntityID}; LogUtil.error(Level.INFO, LogUtil.INVALID_PDP_ID, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("nullPDP")); } if (request != null) { // set properties in the request. XACMLAuthzDecisionQuery xacmlQuery = (XACMLAuthzDecisionQuery) request; if (xacmlQuery != null) { // set Issuer Issuer issuer = createIssuer(pepEntityID); xacmlQuery.setIssuer(issuer); // generate ID String requestID = SAML2SDKUtils.generateID(); xacmlQuery.setID(requestID); xacmlQuery.setVersion(SAML2Constants.VERSION_2_0); xacmlQuery.setIssueInstant(new Date()); XACMLPDPConfigElement pdpConfig = getPDPConfig(realm, pdpEntityID); if (pdpConfig != null) { String wantQuerySigned = getAttributeValueFromPDPConfig(pdpConfig, "wantXACMLAuthzDecisionQuerySigned"); if (wantQuerySigned != null && wantQuerySigned.equals("true")) { signAttributeQuery(xacmlQuery, realm, pepEntityID, false); } } String xmlString = xacmlQuery.toXMLString(true, true); if (debug.messageEnabled()) { debug.message(classMethod + "XACML Query XML String :" + xmlString); } // retrieve endpoint from meta data String endPoint = null; XACMLAuthzDecisionQueryConfigElement pepConfig = getPEPConfig(realm, pepEntityID); endPoint = getPDPEndPoint(pdpEntityID); if (debug.messageEnabled()) { debug.message(classMethod + " ResponseLocation is :" + endPoint); } // create SOAP message try { String soapMessage = SAML2SDKUtils.createSOAPMessageString(xmlString); endPoint = SAML2SDKUtils.fillInBasicAuthInfo(pepConfig, endPoint); String[] urls = {endPoint}; SOAPClient soapClient = new SOAPClient(urls); if (debug.messageEnabled()) { debug.message(classMethod + "soapMessage :" + soapMessage); } InputStream soapIn = soapClient.call(soapMessage, null, null); StringBuffer reply = new StringBuffer(); String line; BufferedReader reader = new BufferedReader(new InputStreamReader(soapIn, "UTF-8")); while ((line = reader.readLine()) != null) { reply.append(line).append("\n"); } // check the SOAP message for any SOAP related errors // before passing control to SAML processor xmlString = reply.toString(); if (debug.messageEnabled()) { debug.message("Response Message:\n" + xmlString); } samlResponse = getSAMLResponse(xmlString); issuer = samlResponse.getIssuer(); String issuerID = null; if (issuer != null) { issuerID = issuer.getValue().trim(); } boolean isTrusted = verifyResponseIssuer(realm, pepEntityID, issuerID); if (!isTrusted) { if (debug.messageEnabled()) { debug.message(classMethod + "Issuer in Request is not valid."); } String[] args = {realm, pepEntityID, pdpEntityID}; LogUtil.error(Level.INFO, LogUtil.INVALID_ISSUER_IN_PEP_REQUEST, args); throw new SAML2Exception("invalidIssuerInRequest"); } if (samlResponse != null) { xmlString = samlResponse.toXMLString(true, true); if (debug.messageEnabled()) { debug.message(classMethod + "Response: " + xmlString); } response = verifyResponse(realm, pepEntityID, samlResponse); if (debug.messageEnabled()) { debug.message( classMethod + "Response with decrypted Assertion: " + response.toXMLString(true, true)); } } } catch (SOAPException soae) { if (debug.messageEnabled()) { debug.message(classMethod + "SOAPException :", soae); } throw new SAML2Exception(soae.getMessage()); } catch (Exception e) { if (debug.messageEnabled()) { debug.message(classMethod + "Exception ", e); } throw new SAML2Exception(e.getMessage()); } } } return response; }
/** * Returns SAMLv2 <code>Response</code> after validation of the response. A new <code>Response * </code> object is created which contains decrypted assertion if the assertions were encrypted. * * @param realm the realm of the entity. * @param pepEntityID entity identifier of the PEP. * @param samlResponse the <code>Response</code>. * @exception <code>SAML2Exception</code> if there is an error. */ private static Response verifyResponse(String realm, String pepEntityID, Response samlResponse) throws SAML2Exception { Response response = samlResponse; String classMethod = "QueryClient:verifyResponse"; if (samlResponse != null) { // validate issuer trust. Issuer issuer = samlResponse.getIssuer(); String issuerID = null; if (issuer != null) { issuerID = issuer.getValue().trim(); } String pdpEntityID = issuerID; boolean isTrusted = verifyResponseIssuer(realm, pepEntityID, issuerID); if (!isTrusted) { if (debug.messageEnabled()) { debug.message(classMethod + "Issuer in Request is not valid."); } String[] args = {realm, pepEntityID, issuerID}; LogUtil.error(Level.INFO, LogUtil.INVALID_ISSUER_IN_PEP_REQUEST, args); throw new SAML2Exception(SAML2SDKUtils.BUNDLE_NAME, "invalidIssuer", args); } // verify signed response verifySignedResponse(pepEntityID, pdpEntityID, samlResponse); try { // check if assertion needs to be encrypted,signed. XACMLAuthzDecisionQueryConfigElement pepConfig = saml2MetaManager.getPolicyEnforcementPointConfig(realm, pepEntityID); String assertionEncrypted = getAttributeValueFromPEPConfig(pepConfig, SAML2Constants.WANT_ASSERTION_ENCRYPTED); boolean wantAssertionEncrypted = (assertionEncrypted != null && assertionEncrypted.equalsIgnoreCase("true")) ? true : false; boolean wantAssertionSigned = wantAssertionSigned(realm, pepEntityID); String respID = samlResponse.getID(); List assertions = samlResponse.getAssertion(); if (wantAssertionEncrypted && (assertions != null && (assertions.size() != 0))) { String[] data = {issuerID, respID}; LogUtil.error(Level.INFO, LogUtil.ASSERTION_FROM_PDP_NOT_ENCRYPTED, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("assertionNotEncrypted")); } PrivateKey decryptionKey = null; List encAssertions = samlResponse.getEncryptedAssertion(); List decAssertions = null; if (encAssertions != null) { Iterator encIter = encAssertions.iterator(); while (encIter.hasNext()) { if (decryptionKey == null) { decryptionKey = KeyUtil.getDecryptionKey(pepConfig); } Assertion assertion = ((EncryptedAssertion) encIter.next()).decrypt(decryptionKey); if (assertions == null) { assertions = new ArrayList(); } assertions.add(assertion); } } if (assertions == null || assertions.size() == 0) { if (debug.messageEnabled()) { debug.message(classMethod + "no assertion in the Response."); } String[] data = {issuerID, respID}; LogUtil.error(Level.INFO, LogUtil.MISSING_ASSERTION_IN_PDP_RESPONSE, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("missingAssertion")); } // validate Issuer in Assertion Iterator assertionIter = assertions.iterator(); X509Certificate cert = null; XACMLPDPDescriptorElement pdpDesc = null; if (wantAssertionSigned) { pdpDesc = saml2MetaManager.getPolicyDecisionPointDescriptor(realm, pdpEntityID); cert = KeyUtil.getPDPVerificationCert(pdpDesc, pdpEntityID); } while (assertionIter.hasNext()) { Assertion assertion = (Assertion) assertionIter.next(); String assertionID = assertion.getID(); String assertionIssuer = assertion.getIssuer().getValue().trim(); isTrusted = verifyResponseIssuer(realm, pepEntityID, assertionIssuer); if (!isTrusted) { debug.error(classMethod + "Assertion's source site is not valid."); String[] data = {assertionIssuer, assertionID}; LogUtil.error(Level.INFO, LogUtil.INVALID_ISSUER_IN_ASSERTION_FROM_PDP, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("invalidIssuerInAssertion")); } String respIssuer = samlResponse.getIssuer().getValue().trim(); if (!respIssuer.equals(assertionIssuer)) { if (debug.messageEnabled()) { debug.message( classMethod + "Issuer in Assertion " + assertionIssuer + "doesn't match the Issuer in Response." + respIssuer); } String[] data = {pdpEntityID, assertionIssuer}; LogUtil.error(Level.INFO, LogUtil.MISMATCH_ISSUER_IN_ASSERTION_FROM_PDP, data); throw new SAML2Exception(SAML2SDKUtils.bundle.getString("mismatchIssuer")); } if (wantAssertionSigned) { if (debug.messageEnabled()) { debug.message(classMethod + "wantAssertionSigned " + wantAssertionSigned); } if (!assertion.isSigned() || !assertion.isSignatureValid(cert)) { debug.error(classMethod + "Assertion is not signed or signature " + "is not valid."); String[] data = {assertionIssuer, assertionID}; LogUtil.error(Level.INFO, LogUtil.INVALID_SIGNATURE_ASSERTION_FROM_PDP, data); throw new SAML2Exception( SAML2SDKUtils.bundle.getString("invalidSignatureOnAssertion")); } } } // end while if (wantAssertionEncrypted) { response = createResponse(samlResponse, assertions); } if (debug.messageEnabled()) { debug.message(classMethod + " Response : " + response.toXMLString(true, true)); } } catch (SAML2MetaException sme) { if (debug.messageEnabled()) { debug.message(classMethod + "Error retreiving meta", sme); } throw new SAML2Exception(SAML2SDKUtils.bundle.getString("metaDataError")); } } return response; }