Package com.sun.enterprise.security.jauth

Source Code of com.sun.enterprise.security.jauth.BaseAuthConfig$ExplicitNull

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.security.jauth;

import java.lang.reflect.Method;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import javax.security.auth.callback.CallbackHandler;

import com.sun.enterprise.security.jauth.AuthConfig;
import com.sun.enterprise.security.jauth.AuthPolicy;
import com.sun.enterprise.security.jauth.ServerAuthContext;
import com.sun.enterprise.webservice.WsUtil;

import com.sun.enterprise.deployment.WebServiceEndpoint;
import com.sun.enterprise.deployment.MethodDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityBindingDescriptor;
import com.sun.enterprise.deployment.runtime.common.ProtectionDescriptor;

import com.sun.xml.rpc.spi.runtime.StreamingHandler;

import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;

/**
* This class is the container's base interface to the AuthConfig subsystem
* to get AuthContext objects on which to invoke message layer authentication
* providers. It is not intended to be layer or web services specific (see
* getMechanisms method at end).
* The ServerAuthConfig and ClientAuthConfig classes extend this class.
*/
public class BaseAuthConfig {

    private static Logger logger = LogDomains.getLogger(LogDomains.SECURITY_LOGGER);

    private Object defaultContext_;

    // holds protected msd that applies to all methods (if there is one)
    private MessageSecurityDescriptor superMSD_;
    private int superIndex_;

    private ArrayList contexts_;

    private ArrayList messageSecurityDescriptors_;

    private ArrayList contextsForOpcodes_;

    private HashMap contextsForOpNames_;

    private boolean onePolicy_;

    private Object contextLock = new Object();

    private ExplicitNull explicitNull = new ExplicitNull();

    protected BaseAuthConfig(Object context) {

  defaultContext_ = context;
  superMSD_ = null;
  superIndex_ = -1;

  messageSecurityDescriptors_ = null;
  contexts_ = null;
  contextsForOpcodes_ = null;
  contextsForOpNames_ = null;
 
  onePolicy_ = true;

  if(logger.isLoggable(Level.FINE)){
      logger.fine("WSS: New BAC defaultContext: " + defaultContext_);
  }
    }

    protected BaseAuthConfig (ArrayList descriptors, ArrayList authContexts) {

  defaultContext_ = null;
  superMSD_ = null;
  superIndex_ = -1;

  messageSecurityDescriptors_ = descriptors;
  contexts_ = authContexts;
  contextsForOpcodes_ = null;
  contextsForOpNames_ = null;

  onePolicy_ = true;

  for (int i = 0; i < descriptors.size(); i++) {

      MessageSecurityDescriptor msd =
    (MessageSecurityDescriptor) descriptors.get(i);

      // determine if all the different messageSecurityDesriptors have the
      // same policy which will help us interpret the effective policy if
      // we cannot determine the opcode of a request at runtime.

      for (int j = 0; j < descriptors.size(); j++) {
    if (j != i && !policiesAreEqual
        (msd,((MessageSecurityDescriptor) descriptors.get(j)))) {
        onePolicy_ = false;
    }
      }
  }

  for (int i = 0; defaultContext_ == null && i < descriptors.size(); i++) {

      MessageSecurityDescriptor msd = (MessageSecurityDescriptor) descriptors.get(i);

      AuthPolicy requestPolicy =
    getAuthPolicy(msd.getRequestProtectionDescriptor());

      AuthPolicy responsePolicy =
    getAuthPolicy(msd.getResponseProtectionDescriptor());

      boolean noProtection = (!requestPolicy.authRequired() &&
            !responsePolicy.authRequired());

      // if there is one policy, and it is null set the associated context as the
      // defaultContext used for all messages.
      if (i==0 && onePolicy_ && noProtection) {
    defaultContext_ = explicitNull;
    break;
      }

      ArrayList mDs = msd.getMessageDescriptors();

      for (int j=0; mDs != null && j < mDs.size(); j++) {
   
    MessageDescriptor mD = (MessageDescriptor) mDs.get(j);
    MethodDescriptor methD = mD.getMethodDescriptor();

    // if any msd covers all methods and operations.
    if ((mD.getOperationName() == null && methD == null) ||
                        (methD != null && methD.getStyle() == 1)) {

        if (onePolicy_) {
      // if there is only one policy make it the default.
      defaultContext_ = contexts_.get(i);
      if (defaultContext_ == null) {
          defaultContext_ = explicitNull;
      }
      break;
        } else if (superIndex_ == -1) {
      // if it has a noProtection policy make it the default.
      if (noProtection) {
          defaultContext_ = explicitNull;
      } else {
          superIndex_ = i;
      }
        } else if (!policiesAreEqual(msd,((MessageSecurityDescriptor)
                  descriptors.get(superIndex_)))) {
      // if there are conflicting policies that cover all methods
      // set the default policy to noProtection
      defaultContext_ = explicitNull;
      superIndex_ = -1;
      break;
        }
    }
      }
  }
  // if there is protected policy that applies to all methods remember the descriptor.
  // Note that the corresponding policy is not null, and thus it is not the default.
  // wherever there is a conflicting policy the effective policy will be noProtection.
  if (superIndex_ >=0) {
      superMSD_ = (MessageSecurityDescriptor) descriptors.get(superIndex_);
  }

  if(logger.isLoggable(Level.FINE)){
      logger.fine("WSS: new BAC defaultContext_: " + defaultContext_ +
      " superMSD index: " + superIndex_ + " onePolicy_: " + onePolicy_);
  }
    }

    protected static AuthPolicy getAuthPolicy(ProtectionDescriptor pd) {
  int sourceAuthType = AuthPolicy.SOURCE_AUTH_NONE;
  boolean recipientAuth = false;
  boolean beforeContent = false;
  if (pd != null) {
      String source = pd.getAttributeValue
    (ProtectionDescriptor.AUTH_SOURCE);
      if (source != null) {
    if (source.equals(AuthPolicy.SENDER)) {
        sourceAuthType = AuthPolicy.SOURCE_AUTH_SENDER;
    } else if (source.equals(AuthPolicy.CONTENT)) {
        sourceAuthType = AuthPolicy.SOURCE_AUTH_CONTENT;
    }
      }
      String recipient = pd.getAttributeValue
    (ProtectionDescriptor.AUTH_RECIPIENT);
      if (recipient != null) {
    recipientAuth = true;
    if (recipient.equals(AuthPolicy.BEFORE_CONTENT)) {
        beforeContent = true;
    } else if (recipient.equals(AuthPolicy.AFTER_CONTENT)) {
        beforeContent = false;
    }
      }
  }
  return new AuthPolicy(sourceAuthType,recipientAuth,beforeContent);
    }

    private static boolean
  isMatchingMSD(MethodDescriptor targetMD, MessageSecurityDescriptor mSD) {
  ArrayList messageDescriptors = mSD.getMessageDescriptors();
  if (messageDescriptors.size() == 0) {
      // If this happens the dd is invalid.
      // Unfortunately the deployment system does not catch such problems.
      // This case will be treated the same as if there was an empty message
      // element, and the deployment will be allowed to succeed.
      return true;
  }

  for (int i=0; i<messageDescriptors.size(); i++) {
      MessageDescriptor nextMD =
    (MessageDescriptor) messageDescriptors.get(i);
      MethodDescriptor mD = nextMD.getMethodDescriptor();
      String opName = nextMD.getOperationName();

      if (opName == null && (mD == null || mD.implies(targetMD))){
    return true;
      }
  }

  return false;
    }

    private static boolean
  policiesAreEqual(MessageSecurityDescriptor reference,
       MessageSecurityDescriptor other) {
  if (!getAuthPolicy
      (reference.getRequestProtectionDescriptor()).equals
      (getAuthPolicy(other.getRequestProtectionDescriptor())) ||

      !getAuthPolicy
      (reference.getResponseProtectionDescriptor()).equals
      (getAuthPolicy(other.getResponseProtectionDescriptor()))) {
     
      return false;
  }
  return true;
    }

    /* When method argument is null, returns the default AC
     * if there is one, or the onePolicy shared by all methods
     * if there is one, or throws an error.
     * method is called with null argument when the method
     * cannot be determined (e.g. when the message is encrypted)
     */
    private Object getContextForMethod(Method m) {
  Object rvalue = null;
  synchronized(contextLock) {
      if (defaultContext_ != null) {
    rvalue = defaultContext_;
    if(logger.isLoggable(Level.FINE)){
        logger.fine("WSS: ForMethod returning default_context: " + rvalue);
    }
    return rvalue;
      }
  }
  if (m != null) {
      int match = -1;
      MethodDescriptor targetMD = new MethodDescriptor(m);
      for (int i = 0; i < messageSecurityDescriptors_.size(); i++) {
    if (isMatchingMSD(targetMD,(MessageSecurityDescriptor)
          messageSecurityDescriptors_.get(i))) {
        if (match < 0) {
      match = i;
        } else if (!policiesAreEqual
             ((MessageSecurityDescriptor)
        messageSecurityDescriptors_.get(match),
        (MessageSecurityDescriptor)
        messageSecurityDescriptors_.get(i))) {

      // set to unprotected because of conflicting policies

      rvalue = explicitNull;
      match = -1;
      if(logger.isLoggable(Level.FINE)){
          logger.fine("WSS: ForMethod detected conflicting policies: " +
          match + "." + i);
      }
      break;
        }
    }
      }
      if (match >= 0) {
    rvalue = contexts_.get(match);
    if (rvalue == null) {
        rvalue = explicitNull;
    }
    if(logger.isLoggable(Level.FINE)){
        logger.fine("WSS: ForMethod returning matched context: " + rvalue);
    }
      }
  } else if (onePolicy_ && contexts_.size() > 0) {
       // ISSUE: since the method is undefined we will not be
      // able to tell if the defined policy covers this method.
       // We will be optimistic and try the policy, because
       // the server will reject the call if the method is not
       // covered by the policy.
       // If the policy is not null, there remains a problem at the
      // client on the response side, as it is possible that the
      // client will enforce the wrong policy on the response.
       // For this reason, messages in sun-application-client.xml
      // should be keyed by operation-name.

      rvalue = contexts_.get(0);
      if(logger.isLoggable(Level.FINE)){
    logger.fine("WSS: ForMethod resorting to first context: " + rvalue);
      }
  } else {
      if(logger.isLoggable(Level.FINE)){
          logger.fine("WSS: Unable to select policy for SOAP Message");
            }
      throw new RuntimeException("Unable to select policy for Message");
  }
  return rvalue;
    }

    // determine if all methods are covered by an AuthCOntext (i.e policy)
    // so that we can tell if there is one policy that covers all.
    private boolean methodIsCovered(Method m) {
  boolean rvalue = true;
  if (messageSecurityDescriptors_ != null) {
      MethodDescriptor targetMD = new MethodDescriptor(m);
      for (int i = 0; i < messageSecurityDescriptors_.size(); i++) {
    if (i == 0) {
        rvalue = false;
    }
    if (isMatchingMSD(targetMD,(MessageSecurityDescriptor)
          messageSecurityDescriptors_.get(i))) {
        rvalue = true;
        break;
    }
      }
  }
  return rvalue;
    }

    private Object getExplicitContextForOpCode(StreamingHandler handler,
  int opcode) throws ClassNotFoundException, NoSuchMethodException {

  Object rvalue = null;

  synchronized(contextLock) {

      if (contextsForOpcodes_ == null && defaultContext_ == null) {

    // one time initialization of the opcode to authContext array.

    boolean onePolicyForAll = onePolicy_;

    Method m = null;
    for (int i = 0; i == 0 || m != null; i++) {
        if (i == 0) {
      contextsForOpcodes_ = new ArrayList();
        }
        if (handler != null) {
      m = handler.getMethodForOpcode(i);
        }
        if (m != null) {
      Object o = getContextForMethod(m);
      contextsForOpcodes_.add(o);

      // if we find a method that is not covered by a method
      // descriptor (i.e. has an implicit nullPolicy),
      // then we switch off onePolicyForAll (note that
      // ServerAuthConfigs with one policy being the
      // null policy, are not constructed.

      if (o == null) {
          onePolicyForAll = false;
      }
        }
    }
    if (onePolicyForAll && contextsForOpcodes_.size() > 0) {
        defaultContext_ = contextsForOpcodes_.get(0);
    }
      }
      if (defaultContext_ != null) {
    rvalue = defaultContext_;
    if(logger.isLoggable(Level.FINE)){
        logger.fine("WSS: ForOpCode returning default_context: " + rvalue);
    }
      }
  }

  if (rvalue == null) {
      if (opcode >=0 && opcode < contextsForOpcodes_.size()) {
    rvalue = contextsForOpcodes_.get(opcode);
      } else if (opcode < 0) {
    //we don't know the opcode, so lets try to see if
    //there is a policy that applies to all opcodes.
    rvalue = getContextForMethod(null);
      }
  }
  return rvalue;
    }

    protected Object getContextForOpCode(StreamingHandler handler, int opcode)
  throws ClassNotFoundException, NoSuchMethodException {
  Object rvalue = getExplicitContextForOpCode(handler,opcode);
  if (rvalue != null && rvalue instanceof ExplicitNull) {
      rvalue = null;
  }
  return rvalue;
    }

    private static String getOpName(SOAPMessage message) {

  String rvalue = null;

  // first look for a SOAPAction header.
  // this is what .net uses to identify the operation

  MimeHeaders headers = message.getMimeHeaders();
  if (headers != null) {
      String[] actions = headers.getHeader("SOAPAction");
      if (actions != null && actions.length > 0) {
    rvalue = actions[0];
    if (rvalue != null && rvalue.equals("\"\"")) {
        rvalue = null;
    }
      }
  }

  // if that doesn't work then we default to trying the name
  // of the first child element of the SOAP envelope.

  if (rvalue == null) {
      Name name = getName(message);
      if (name != null) {
    rvalue = name.getLocalName();
      }
  }
 
  return rvalue;
    }

    private static String getOpName(SOAPMessageContext soapMC) {

  String rvalue = null;

  // first look for a the property value in the context
  QName qName = (QName) soapMC.get(MessageContext.WSDL_OPERATION);
  if (qName != null) {
      rvalue = qName.getLocalPart();
  } else {
      rvalue = getOpName(WsUtil.getMessageWithName(soapMC));
  }

  return rvalue;
    }

    private Object getContextForOpName(String operation) {

  synchronized(contextLock) {
      if (contextsForOpNames_ == null) {

    // one time initialization of the opName to authContext array.

    contextsForOpNames_ = new HashMap();
    for (int i=0; messageSecurityDescriptors_ != null &&
       i < messageSecurityDescriptors_.size(); i++) {
       
        MessageSecurityDescriptor mSD = (MessageSecurityDescriptor)
      messageSecurityDescriptors_.get(i);

        ArrayList mDs = mSD.getMessageDescriptors();

        for (int j=0; mDs != null && j < mDs.size(); j++) {

      MessageDescriptor mD = (MessageDescriptor) mDs.get(j);
      String opName = mD.getOperationName();

      if (opName != null) {

          if (contextsForOpNames_.containsKey(opName)) {

        Integer k = (Integer) contextsForOpNames_.get(opName);
        if (k != null) {

            MessageSecurityDescriptor other =
          (MessageSecurityDescriptor)
          messageSecurityDescriptors_.get(k.intValue());

            // set to null if different policies on operation

            if (!policiesAreEqual(mSD,other)) {
          contextsForOpNames_.put(opName,null);
            }
        }
          } else if (superMSD_!=null && !policiesAreEqual(mSD,superMSD_)){
        // set to null if operation policy differs from superPolicy
        contextsForOpNames_.put(opName,null);
          } else {
        contextsForOpNames_.put(opName,new Integer(i));
          }
      }
        }
    }
      }
  }

  Object rvalue = null;
  if (operation != null) {
      if (contextsForOpNames_.containsKey(operation)) {
    Integer k = (Integer) contextsForOpNames_.get(operation);
    if (k != null) {
        rvalue = contexts_.get(k.intValue());
    }
      } else if (superIndex_ >= 0) {
                // if there is a msb that matches all methods, use the
                // associatedContext
                rvalue = contexts_.get(superIndex_);
      }

            if (rvalue == null) {
                // else return explicitNull under the assumption
                // that methodName was known, and no match was found
                rvalue = explicitNull;
            }
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("WSS: ForOpName=" + operation + " context: " + rvalue);
            }
  }
  return rvalue;
    }
   
    // DO NOT CALL THIS ON THE SERVER SIDE, as it will return a null
    // context if there is no default context and there isn't a message
    // element defined with the corresponding operation name (even though the
    // corresponding method may be protected).
    //
    // This method is intended to be used by clients where it serves as a
    // work-around for not being able to map the message to the method (due
    // to lack of access to a streaming handler equivalent).
    //
    // This method will not be called when the handler argument passed in
    // a call to getContext or getContextForOpCode is not null.
    // Thus, server-side calls to these methods must pass a non-null
    // handler argument.

    private Object getContextForMessage(SOAPMessage message) {
 
  String opName = getOpName(message);

  Object rvalue = getContextForOpName(opName);
  if (rvalue == null) {

      // opName is not mapped or msg body is encrypted, and the best
      // we can do is try to return a policy that applies to all
      // operations, if there is one.
     
      rvalue = getContextForMethod(null);

  }
  return rvalue;
    }
   
    protected Object getContext(StreamingHandler handler,SOAPMessage message){

  Object rvalue = null;

  synchronized(contextLock) {
      if (defaultContext_ != null) {
    rvalue = defaultContext_;
      }
  }
  if (rvalue == null) {

      if (handler == null) {

    // lack of handler precludes mapping to opcode, so we will
    // look for an opName based mapping.

    rvalue = getContextForMessage(message);

      } else {

    int opCode = handler.getOpcodeForRequestMessage(message);

    if (opCode == -1) {

        // msg body is encrypted, and the best we can do is try
        // to return a policy that applies to all opcodes.

        rvalue = getContextForMethod(null);

    } else {
       
        try {
      rvalue = getExplicitContextForOpCode(handler,opCode);
       
      // if unable to get context by opcode
      // see if a context was defined for the opName.
       
      if (rvalue == null) {

          rvalue = getContextForMessage(message);

      }
        } catch (ClassNotFoundException cnfe) {
      throw new RuntimeException(cnfe);
        } catch (NoSuchMethodException nsme) {
      throw new RuntimeException(nsme);
        }
    }
      }
  }

  if (rvalue != null && rvalue instanceof ExplicitNull) {
      rvalue = null;
  }

  if(logger.isLoggable(Level.FINE)){
      logger.fine("WSS: getContext returning: " + rvalue);
  }

  return rvalue;
    }

    // used by jaxws system handler delegates and handlers
    protected Object getContext(SOAPMessageContext soapMC) {

  Object rvalue = null;

  synchronized(contextLock) {
      if (defaultContext_ != null) {
    rvalue = defaultContext_;
      }
  }

  if (rvalue == null) {

      Method m = getMethod(soapMC);
      String opName = null;

      if (m != null) {
    rvalue = getContextForMethod(m);
      }

      if (rvalue == null) {
    opName = getOpName(soapMC);
    if (opName != null) {
        rvalue = getContextForOpName(opName);
    }
      }

      if (rvalue == null && (m == null || opName == null)) {

    //we were unable to determine either method or
    // opName, so lets see if one policy applies to all

    rvalue = getContextForMethod(null);
      }
  }
 
  if (rvalue != null && rvalue instanceof ExplicitNull) {
      rvalue = null;
  }

  return rvalue;
    }

    private static Name getName(SOAPMessage message) {
  Name rvalue = null;
  SOAPPart soap = message.getSOAPPart();
  if (soap != null) {
      try {
    SOAPEnvelope envelope = soap.getEnvelope();
    if (envelope != null) {
        SOAPBody body = envelope.getBody();
        if (body != null) {
      Iterator it = body.getChildElements();
      while (it.hasNext()) {
          Object o = it.next();
          if (o instanceof SOAPElement) {
        rvalue = ((SOAPElement) o).getElementName();
        break;
          }
      }
        }
    }
      } catch (SOAPException se) {
    if(logger.isLoggable(Level.FINE)){
        logger.log(Level.FINE,"WSS: Unable to get SOAP envelope",
             se);
    }
      }
  }
 
  return rvalue;
    }

    public static Method getMethod(SOAPMessageContext soapMC) {

        // It should never come here
  return null;
    }

    // each instance of AuthConfig maps to one provider
    // configuration, either via a message-security-binding, or a default
    // provider-config.

    // mechanisms are temporarily encapsulated here, until a method that
    // returns the list of supported mechanisms is added to
    // jauth.ServerAuthContext and jauth.ClientAuthContext.
    public QName[] getMechanisms() {
  return mechanisms;
    }

    // WSS security header QName
    private static QName mechanisms[] = new QName[] {
  new QName( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "wsse") };

    // internal class used to differentiate not protected from policy undefined or
    // not determined.

    class ExplicitNull {

  ExplicitNull() {
  }

  public boolean equals(Object other) {
      return (other != null && other instanceof ExplicitNull ? true : false);
  }

  public String toString() {
      return "ExplicitNull";
  }
    }
}
TOP

Related Classes of com.sun.enterprise.security.jauth.BaseAuthConfig$ExplicitNull

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.