Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Summary of issues with the current arrangement

  • Better separation of policy model from assembly model
    • implementation policy sets held by component due to reuse of implementation model objects
    • OASIS are talking about moving to an external attachment model so we need flexibility to follow that move if necessary
  • "Applies to" happens right at the start of contribution and is not subject to later builder processing
  • Consistency of model style between assembly and policy models
  • Separate any policy processing from policy model
  • Consistency of policy extension model
  • definitions.xml processing should be domain wide and not restricted to a single contribution

Idealistic policy model

The make sure I understand the model I reproduced my version of it from the existing spec resources. It's slightly different from what we have at present as the code model is somewhat optimized but I want to use this as my baseline for reviewing what we have in the implementations

Image Added

Image AddedImage Removed

Policy model reading follows the assembly model in having read and resolve phases. The read phase will create dummy objects with "unresolved = true" set to represent any unresolved references. These dummy objects are replaced with the real thing at the resolve stage.

...

The assembly model starts life with manually configured intents and policy sets on individual assembly elements. The result of applying the intent and policySet inheritance rules and the intent and policySet matching rules leads to a final set of relationships between assembly artifacts and policySets. I started to draw these externalized from the assembly model but expect that they will resolve to placing the correct policySet QNames on appropriate assembly artifacts. These relationships drive the configuration of each binding and implementation and with wires in between.

Image RemovedImage Added

Policy touch points

...

These steps require a closer integration between the bindings and the policy providers than we have currently.

Example of how binding.ws is configured in this scenario

Image Added

Authentication - HTTP Basic

...

Need same capability as described in single sign on to get close to the web service binding and configure the transport (reference side) extract transport context (service side).

Definitions.xml

Code Block

    <sca:policySet name="WSBasicAuthenticationPolicySet"
                   provides="authentication"
                   appliesTo="sca:reference/sca:binding.ws">
                   
        <tuscany:wsBasicAuthentication>
          <tuscany:userName>myname</tuscany:userName>
          <tuscany:password>mypassword</tuscany:password>
        </tuscany:wsBasicAuthentication>
        
     	<tuscany:wsAxisOption>
                <propertySetter name="org.apache.tuscany.sca.binding.ws.axis2.policy.authentication.basic.WSBasicAuthenticationReferencePolicyAxisOptions"/>
     		<property name="_NTLM_DIGEST_BASIC_AUTHENTICATION_"/>
                <authenticator>
                   <authScheme>Basic</authScheme>
                   <premtiveAuthentication>true</premtiveAuthentication>
                </authenticator>
          	</property>
     	</tuscany:wsAxisOption>
        
    </sca:policySet>
    
    <sca:policySet name="WSBasicAuthenticationPolicySet"
                   provides="authentication"
                   appliesTo="sca:service/sca:binding.ws">
                   
        <tuscany:wsBasicAuthentication>
          <tuscany:userName>myname</tuscany:userName>
          <tuscany:password>mypassword</tuscany:password>
        </tuscany:wsBasicAuthentication>
        
    </sca:policySet>   

Reference side interceptor:

Code Block

public class WSBasicAuthenticationReferencePolicyInterceptor implements Interceptor {
    public static final QName policySetQName = new QName(Constants.SCA10_TUSCANY_NS, "wsBasicAuthentication");

    private Invoker next;
    private Operation operation;
    private PolicySet policySet = null;
    private String context;
    private WSBasicAuthenticationPolicy policy;

    public WSBasicAuthenticationReferencePolicyInterceptor(String context, Operation operation, PolicySet policySet) {
        super();
        this.operation = operation;
        this.policySet = policySet;
        this.context = context;
        init();
    }

    private void init() {
        if (policySet != null) {
            for (Object policyObject : policySet.getPolicies()){
                if (policyObject instanceof WSBasicAuthenticationPolicy){
                    policy = (WSBasicAuthenticationPolicy)policyObject;
                    break;
                }
            }
        }
    }

    public Message invoke(Message msg) {
        // could call out here to some 3rd part system to get credentials
        msg.getQoSContext().put(WSBasicAuthenticationPolicy.WS_BASIC_AUTHENTICATION_USERNAME,
                                policy.getUserName());
        msg.getQoSContext().put(WSBasicAuthenticationPolicy.WS_BASIC_AUTHENTICATION_PASSWORD,
                policy.getPassword());
        
        return getNext().invoke(msg);
    }

    public Invoker getNext() {
        return next;
    }

    public void setNext(Invoker next) {
        this.next = next;
    }
}

Service side interceptor

Code Block

public class WSBasicAuthenticationServicePolicyInterceptor implements Interceptor {
    public static final QName policySetQName = new QName(Constants.SCA10_TUSCANY_NS, "wsBasicAuthentication");

    private Invoker next;
    private Operation operation;
    private PolicySet policySet = null;
    private String context;
    private WSBasicAuthenticationPolicy policy;

    public WSBasicAuthenticationServicePolicyInterceptor(String context, Operation operation, PolicySet policySet) {
        super();
        this.operation = operation;
        this.policySet = policySet;
        this.context = context;
        init();
    }

    private void init() {
        if (policySet != null) {
            for (Object policyObject : policySet.getPolicies()){
                if (policyObject instanceof WSBasicAuthenticationPolicy){
                    policy = (WSBasicAuthenticationPolicy)policyObject;
                    break;
                }
            }
        }
    }

    public Message invoke(Message msg) {
        Object[] header = msg.getHeader();
        
        Map httpHeaderProperties = (Map)Object[0];
        
        String basicAuthString = (String)httpHeaderProperties.get("Authorization");
        String decodedBasicAuthString = null;
        String username = null;
        String password = null;
        
        if (basicAuthString != null) {
            basicAuthString = basicAuthString.trim();
            
            if (basicAuthString.startsWith("Basic ")) {
                decodedBasicAuthString = new String(Base64.decode(basicAuthString.substring(6)));
            }
            
            int collonIndex = decodedBasicAuthString.indexOf(':');
            
            if (collonIndex == -1){
                username = decodedBasicAuthString;
            } else {
                username = decodedBasicAuthString.substring(0, collonIndex);
                password = decodedBasicAuthString.substring(collonIndex + 1);
            }
            
            // could call out here to some 3rd part system to do whatever you 
            // need to turn credentials into a principal            
            
            msg.getQoSContext().put(Message.QOS_CTX_SECURITY_PRINCIPAL, username);             
        }
    
        return getNext().invoke(msg);
    }

    public Invoker getNext() {
        return next;
    }

    public void setNext(Invoker next) {
        this.next = next;
    }
}
Code Block

public class WSBasicAuthenticationReferencePolicyAxisOptions {
    
    public WSBasicAuthenticationReferencePolicyAxisOptions(){
    }
    
    public void setServiceOptions(ServiceClient serviceClient) {
    }
    
    public void setOperationOptions(OperationClient operationClient, Message msg) {
        
        // get security context
        String securityPrincipal = (String)msg.getQoSContext().get(Message.QOS_CTX_SECURITY_PRINCIPAL);
        String username = null;
        String password = null;
        
        // could use the security principal to look up basic auth credentials
        if (  securityPrincipal != null ) {
            // look up usename and password based on security principal
        } else {
           // take the message username and password
            username = (String)msg.getQoSContext().get(WSBasicAuthenticationPolicy.WS_BASIC_AUTHENTICATION_USERNAME);
            password = (String)msg.getQoSContext().get(WSBasicAuthenticationPolicy.WS_BASIC_AUTHENTICATION_PASSWORD);
        }
        
        if (username == null || password == null ){
            throw new ServiceRuntimeException("Basic authenication username or password is null");
        }
        
        HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
        List<String> auth = new ArrayList<String>();
        auth.add(Authenticator.BASIC);
        authenticator.setAuthSchemes(auth);
        authenticator.setPreemptiveAuthentication(true);
        authenticator.setUsername(username);
        authenticator.setPassword(password);
    
        operationClient.getOptions().setProperty(HTTPConstants.AUTHENTICATE,
                                                 authenticator);
    }
    
    public void setMessageOptions(MessageContext messageContext) {
        
    }

}

Confidentiality - WS Security

...