Package org.apache.cxf.ws.security.wss4j

Source Code of org.apache.cxf.ws.security.wss4j.AbstractUsernameTokenAuthenticatingInterceptor$CustomValidator

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.ws.security.wss4j;

import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.security.auth.Subject;
import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.security.SecurityToken;
import org.apache.cxf.common.security.UsernameToken;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.security.DefaultSecurityContext;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.security.SecurityContext;
import org.apache.ws.security.WSSecurityEngine;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.handler.RequestData;
import org.apache.ws.security.validate.UsernameTokenValidator;
import org.apache.ws.security.validate.Validator;


/**
* Base class providing an extensibility point for populating
* javax.security.auth.Subject from a current UsernameToken.
*
* WSS4J requires a password for validating digests which may not be available
* when external security systems provide for the authentication. This class
* implements WSS4J Processor interface so that it can delegate a UsernameToken
* validation to an external system.
*
* In order to handle digests, this class currently creates a new WSS4J Security Engine for
* every request. If clear text passwords are expected then a supportDigestPasswords boolean
* property with a false value can be used to disable creating security engines.
*
* Note that if a UsernameToken containing a clear text password has been encrypted then
* an application is expected to provide a password callback handler for decrypting the token only.    
*
*/
public abstract class AbstractUsernameTokenAuthenticatingInterceptor extends WSS4JInInterceptor {
   
    private static final Logger LOG =
        LogUtils.getL7dLogger(AbstractUsernameTokenAuthenticatingInterceptor.class);
   
    private boolean supportDigestPasswords;
   
    public AbstractUsernameTokenAuthenticatingInterceptor() {
        this(new HashMap<String, Object>());
    }
   
    public AbstractUsernameTokenAuthenticatingInterceptor(Map<String, Object> properties) {
        super(properties);
        getAfter().add(PolicyBasedWSS4JInInterceptor.class.getName());
    }
   
    public void setSupportDigestPasswords(boolean support) {
        supportDigestPasswords = support;
    }
   
    public boolean getSupportDigestPasswords() {
        return supportDigestPasswords;
    }
   
    @Override
    public void handleMessage(SoapMessage msg) throws Fault {
        SecurityToken token = msg.get(SecurityToken.class);
        SecurityContext context = msg.get(SecurityContext.class);
        if (token == null || context == null || context.getUserPrincipal() == null) {
            super.handleMessage(msg);
            return;
        }
        UsernameToken ut = (UsernameToken)token;
       
        Subject subject = createSubject(ut.getName(), ut.getPassword(), ut.isHashed(),
                                        ut.getNonce(), ut.getCreatedTime());
       
        SecurityContext sc = doCreateSecurityContext(context.getUserPrincipal(), subject);
        msg.put(SecurityContext.class, sc);
    }
   
    @Override
    protected SecurityContext createSecurityContext(final Principal p) {
        Message msg = PhaseInterceptorChain.getCurrentMessage();
        if (msg == null) {
            throw new IllegalStateException("Current message is not available");
        }
        return doCreateSecurityContext(p, msg.get(Subject.class));
    }
   
    /**
     * Creates default SecurityContext which implements isUserInRole using the
     * following approach : skip the first Subject principal, and then check optional
     * Groups the principal is a member of. Subclasses can override this method and implement
     * a custom strategy instead
     *  
     * @param p principal
     * @param subject subject
     * @return security context
     */
    protected SecurityContext doCreateSecurityContext(final Principal p, final Subject subject) {
        return new DefaultSecurityContext(p, subject);
    }

       
    protected void setSubject(String name,
                              String password,
                              boolean isDigest,
                              String nonce,
                              String created) throws WSSecurityException {
        Message msg = PhaseInterceptorChain.getCurrentMessage();
        if (msg == null) {
            throw new IllegalStateException("Current message is not available");
        }
        Subject subject = null;
        try {
            subject = createSubject(name, password, isDigest, nonce, created);
        } catch (Exception ex) {
            String errorMessage = "Failed Authentication : Subject has not been created";
            LOG.severe(errorMessage);
            throw new WSSecurityException(errorMessage, ex);
        }
        if (subject == null || subject.getPrincipals().size() == 0
            || !subject.getPrincipals().iterator().next().getName().equals(name)) {
            String errorMessage = "Failed Authentication : Invalid Subject";
            LOG.severe(errorMessage);
            throw new WSSecurityException(errorMessage);
        }
        msg.put(Subject.class, subject);
    }
   
    /**
     * Create a Subject representing a current user and its roles.
     * This Subject is expected to contain at least one Principal representing a user
     * and optionally followed by one or more principal Groups this user is a member of.
     * It will also be available in doCreateSecurityContext.  
     * @param name username
     * @param password password
     * @param isDigest true if a password digest is used
     * @param nonce optional nonce
     * @param created optional timestamp
     * @return subject
     * @throws SecurityException
     */
    protected abstract Subject createSubject(String name,
                                    String password,
                                    boolean isDigest,
                                    String nonce,
                                    String created) throws SecurityException;
   
    @Override
    protected WSSecurityEngine getSecurityEngine(boolean utNoCallbacks) {
        Map<QName, Object> profiles = new HashMap<QName, Object>(1);
       
        Validator validator = new CustomValidator();
        profiles.put(WSSecurityEngine.USERNAME_TOKEN, validator);
        return createSecurityEngine(profiles);
    }
   
    protected class CustomValidator extends UsernameTokenValidator {
       
        @Override
        protected void verifyCustomPassword(
            org.apache.ws.security.message.token.UsernameToken usernameToken,
            RequestData data
        ) throws WSSecurityException {
            AbstractUsernameTokenAuthenticatingInterceptor.this.setSubject(
                usernameToken.getName(), usernameToken.getPassword(), false, null, null
            );
        }
       
        @Override
        protected void verifyPlaintextPassword(
            org.apache.ws.security.message.token.UsernameToken usernameToken,
            RequestData data
        ) throws WSSecurityException {
            AbstractUsernameTokenAuthenticatingInterceptor.this.setSubject(
                usernameToken.getName(), usernameToken.getPassword(), false, null, null
            );
        }
       
        @Override
        protected void verifyDigestPassword(
            org.apache.ws.security.message.token.UsernameToken usernameToken,
            RequestData data
        ) throws WSSecurityException {
            if (!supportDigestPasswords) {
                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
            }
            String user = usernameToken.getName();
            String password = usernameToken.getPassword();
            boolean isHashed = usernameToken.isHashed();
            String nonce = usernameToken.getNonce();
            String createdTime = usernameToken.getCreated();
            AbstractUsernameTokenAuthenticatingInterceptor.this.setSubject(
                user, password, isHashed, nonce, createdTime
            );
        }
       
        @Override
        protected void verifyUnknownPassword(
            org.apache.ws.security.message.token.UsernameToken usernameToken,
            RequestData data
        ) throws WSSecurityException {
            AbstractUsernameTokenAuthenticatingInterceptor.this.setSubject(
                usernameToken.getName(), null, false, null, null
            );
        }
       
    }
   
}
TOP

Related Classes of org.apache.cxf.ws.security.wss4j.AbstractUsernameTokenAuthenticatingInterceptor$CustomValidator

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.