SAMLSOAPReceiver.java revision 4a5a82da9bbab0a3ea1701c3ae9334c678d24ca5
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: SAMLSOAPReceiver.java,v 1.3 2009/06/12 22:21:39 mallas Exp $
*
*/
/*
* Portions Copyrighted 2013 ForgeRock, Inc.
*/
/**
* This class defines a SOAP Receiver which supports SOAP over HTTP binding.
* It's the receiver of SAML requests from external parties for any
* authentication ,authorization or attribute information for a
* <code>Subject</code>.
* Its response which is an <code>Assertion</code> is used by the caller to
* enable an SSO solution or allow access to resource based on the
* <code>Statement</code> contained in the assertion sent by it.
* It supports the following functions:
* <pre>
* 1- Accepts an artifact request and returns corresponding assertion.
* 2- Accepts assertion id request and returns corresponding assertion.
* 3- accept the authentication query and return authentication assertion.
* 4- Accept authorization query and return authorization decision assertion.
* 5- Accept attribute query and return attribute assertion.
* </pre>
**/
public class SAMLSOAPReceiver extends HttpServlet {
/**
* The <code>MessageFactory</code> object that will be used internally
* to create the <code>SOAPMessage</code> object which will be passed to the
* method <code>onMessage</code>. This new message will contain the data
* from the message that was posted to the servlet.
*/
/**
* When initialized it represents ID of the local server. It has the format
* of server_protocol://server_host:server_port.
* It is used to identify whether the system is in server mode or client
* mode.
*/
/**
* Initializes the servlet.
*
* @param config <code>ServletConfig</code> object.
* @throws ServletException if error occurred during initialization.
*/
":" + localServerPort;
// initializing the msgFactory field with a default
// MessageFactory object.
try {
// Initialize it to the default.
} catch (SOAPException ex) {
"missingSoapMessageFactory");
"missingSoapMessageFactory")};
}
}
/**
* Processes request coming from SOAP.
*
* @param req <code>HttpServletRequest</code> object.
* @param resp <code>HttpServletResponse</code> object.
* @throws ServletException if there is an error.
* @throws IOException if there is an error.
*/
// avoid the DOS attack for SOAP messaging
// In case SAML inter-op with other SAML vendor who may not provide
// contentlength in HttpServletRequest. We decide to support no length
// restriction for SOAP messaging. Here, we use a special value
// (e.g. 0) to indicate that no enforcement is required.
if (length == -1) {
throw new ServletException(
}
}
throw new ServletException(
}
}
+ "processing it now..");
}
try {
//Create the SOAPMessage from the reply
if(soapMessageReply != null){
if(soapMessageReply.saveRequired())
//Check to see if presence of SOAPFault
"Contains a SOAPFault!");
}
} else {
}
//Send the response back to the senderby placing
//the mime headers into the response, and
//externalizing the soapmessage onto the response object
}
} catch(Exception e){
throw new ServletException(e);
}
} else {
// its not trusted site
+remoteAddr+ " is untrusted site");
try {
} catch (SOAPException se) {
throw new ServletException(se);
}
}
}
/**
* containsFault is a utiltiy method to see if msg contains a soapfault.
*/
try{
}catch(Exception e){
}
return false;
}
}
/**
* Retrieves the SAML <code>Request</code> from the
* <code>SOAPMessage</code>, calls internal methods to parse the
* <code>Request</code> generate SAML <code>Response</code> and send it
* back to the requestor again using SOAP binding over HTTP.
*/
// first check if there was any soap error during verifyHost()
try {
+ "servlet");
}
// check the SOAP message for any SOAP
// related errros before passing control to SAML processor
+ " SOAPMessage passed seems to be missing");
"LocalNameMissing");
}
+ "SOAPMessage, either root element is not Envelope"
+ " or invalid name space or prefix");
"envelopeInvalid");
}
if (length <=0 ) {
+ "body");
}
for (int i = 0; i < length; i++) {
continue;
}
break; // found the message body
}
}
{
}
} catch(Exception e) {
"cannotProcessRequest", null);
}
}
/**
* Extracts the Request object from the SOAPMessage return corresponding
* response.
*/
+remoteAddr+": ";
"Request");
if (length == 0 ) {
try {
contents);
} catch ( SAMLException se ) {
}
return retResponse;
}
boolean foundRequest = false;
for (int i = 0; i < length; i++) {
continue;
}
try {
}
foundRequest = true;
break;
} catch ( SAMLRequesterException ss) {
}
try {
} catch ( SAMLException se ) {
+ "cannot create status or response:"
+ se.getMessage());
}
return retResponse;
} catch ( SAMLRequestVersionTooHighException sv) {
}
try {
contents);
} catch ( SAMLException se ) {
+ "cannot create status or response:"
+ se.getMessage());
}
return retResponse;
} catch ( SAMLRequestVersionTooLowException sv) {
}
try {
contents);
} catch ( SAMLException se ) {
+ "cannot create status or response:"
+ se.getMessage());
}
return retResponse;
} catch (Exception e ) {
}
try {
} catch ( SAMLException se ) {
+ "cannot create status or response:"
+ se.getMessage());
}
return retResponse;
}
}
}
if (!(foundRequest)) {
try {
} catch ( SAMLException se ) {
+ "cannot create status or response:"
+ se.getMessage());
}
return retResponse;
} else { // found request now process it
if (!req.isSignatureValid()) {
+ "the signature on Request.");
}
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
}
+ "element in the request which are not supported");
}
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
}
if (!parseRespondWith(respondWith)) {
+ "are not present in the RespondWith element.");
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
}
try {
} catch (SAMLException se ) {
+ " instantiate AssertionManager");
}
try {
} catch ( SAMLException sse ) {
+ "cannot create status or response", sse);
"cannotBuildResponse")};
}
return retResponse;
}
// ensure that all the artifacts have this site's sourceID
for (int j = 0; j < length; j++) {
+ " has invalid SourceID");
}
"mismatchSourceID");
try {
} catch ( SAMLException ex ) {
+ "Fatal error, "
+ "cannot create status or response", ex);
"cannotBuildResponse")};
}
return retResponse;
}
} // for loop to go through artifacts to check for sourceID
for (int i = 0; i < length; i++) {
try {
} catch (SAMLException se ) {
+ " could not find matching assertion");
}
try {
} catch ( SAMLException sse ) {
+ "cannot create status or response", sse);
"cannotBuildResponse")};
}
return retResponse;
}
}
}
for (int i = 0; i < length; i++) {
try {
} catch (SAMLException se ) {
+ " could not find matching assertion");
}
try {
} catch ( SAMLException sse ) {
+ "cannot create status or response", sse);
"cannotBuildResponse")};
}
return retResponse;
}
}
}
{
try {
// if we come here, partnerSourceID is not empty
// always pass the first matching sourceID in
// need to find solution to handle multiple matches:TBD
} catch (SAMLException se ) {
+ " could not find matching assertion");
}
try {
} catch ( SAMLException sse ) {
+ " error, cannot create status or "
+ " response", sse);
"cannotBuildResponse")};
}
return retResponse;
}
}
}
} else { //
+ "contents has element which is not supported at this"
+ " time");
}
"unsupportedElement");
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
}
}
// check to see of the statements inside the assertion are not
// different from what exists in the RespondWith element of the
// Request received.
for (int i = 0; i < assertionSize; i++) {
return resp;
} // else there was no mismatch with respondWith element
}
+ "Assertion found");
}
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
} else {
try {
//contents = null;
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
}
} else { // build response for all the other type of request
try {
} catch ( SAMLException se ) {
+ "cannot create status or response", se);
"cannotBuildResponse")};
}
}
} // end of else found request
if (LogUtils.isAccessLoggable(
} else {
}
return retResponse;
}
/**
* This method forms a SOAP Fault and puts it in the SOAP Message's
* Body.
*/
try {
"Problem"));
}
} catch ( SOAPException e ) {
}
return msg;
}
/**
* This message forms the SAML Response and puts it in the
* SOAPMessage's Body.
*/
try {
}
} catch (Exception e ) {
"cannotVerifyIdentity");
}
return msg;
}
/**
* This method validates the assertion to see that the statements it
* contains are what is present in the RespondWith element of the
* corresponsing Request. If valid adds the passed assertion in the
* passed contents, which is a List, at the specified index.
*/
+ " any statements in it");
try {
contents);
} catch ( SAMLException se ) {
+ "create status or response", se);
"cannotBuildResponse")};
}
return retResponse;
} else { // statements not empty
boolean mismatchError = false; // would be true if there is any
// mismatch with RespondWith contents.
} else {
if (!mismatchError) {
}
} // end of else respondWith size > 0
if (mismatchError) {
+ " meet respondWith criteria in the received Request");
"mismatchRespondWith");
try {
//contents = null;
} catch ( SAMLException se ) {
+ " cannot create status or response", se);
"cannotBuildResponse")};
}
}
} // end of else statements not empty
return null; // reached here, so there was no error in validation
}
/**
* This method takes in the List of respondWith and returns true or
* false based on if the contents of the respondWith element
* contains Statement types supported by the Receiver
*/
return false;
} else {
{
return false;
}
}
}
return true;
}
/**
* This method takes in a RespondWith element ( List) and a statement List
* and returns true or false depending on whether the all statement types
* exist in the RespondWith List
*/
boolean stFound= false;
stFound = false;
+respWith);
switch (st.getStatementType()) {
stFound = true;
}
break;
":AuthorizationDecisionStatement")) {
stFound = true;
}
break;
case Statement.ATTRIBUTE_STATEMENT:
stFound = true;
}
break;
}
if (stFound) {
break;
}
}
if (!stFound) {
return false;
}
}
return true;
}
/**
* Protected method to check the caller to the servlet.
* Returns a set of sourceid whose hostlist contains the passed in
* certificate's nick name or HttpServletRequest's remote IP address if
* valid. Else null is returned.
*/
}
// first see if there is a cert being presented
// if so establish trust with cert, then dont bother about IP addresses
// check if container is secure or not before calling get certificate
// to avoid error in web server log for WS 6.1sp2
try {
} catch (Exception e ) {
}
}
// no cert so use IP address
} else { // cert is present, so verify cert
}
+certOrIP);
}
}
}
return (null);
}
return (partnerSourceID);
}
/**
* This is a private function which goes through the partner URLS and
* locates a set of source ID based on the passed string which is either the
* remote IP address ( if no cert is presented) or is a cert alias if
* SSL with Client auth is on. If there is no match, return null.
*/
if (partnerMap != null) {
}
}
}
return sidSet;
}
return (null);
}
/**
* Verifies if the sourceID passed in the parameter is same
* as this site's site ID.
*/
}
}