Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CXF InInterceptor not firing

I have created web service. It works fine. Now I'm trying to implement authentication to it. I'm using CXF interceptors for that purpose. For some reason interceptors won't fire. What am I missing? This is my first web service.

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;

import org.apache.cxf.interceptor.InInterceptors;

@WebService
@InInterceptors(interceptors = "ws.BasicAuthAuthorizationInterceptor")
public class Service {

    @WebMethod
    public void test(@WebParam(name = "value") Integer value) throws Exception {
        System.out.println("Value = " + value);
    }    
}

-

package ws;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.ws.addressing.EndpointReferenceType;

public class BasicAuthAuthorizationInterceptor extends SoapHeaderInterceptor {

@Override
public void handleMessage(Message message) throws Fault {
    System.out.println("**** GET THIS LINE TO CONSOLE TO SEE IF INTERCEPTOR IS FIRING!!!");
    AuthorizationPolicy policy = message.get(AuthorizationPolicy.class);

    // If the policy is not set, the user did not specify credentials.
    // 401 is sent to the client to indicate that authentication is required.
    if (policy == null) {
        sendErrorResponse(message, HttpURLConnection.HTTP_UNAUTHORIZED);
        return;
    }

    String username = policy.getUserName();
    String password = policy.getPassword();

    // CHECK USERNAME AND PASSWORD
    if (!checkLogin(username, password)) {
        System.out.println("handleMessage: Invalid username or password for user: "
                + policy.getUserName());
        sendErrorResponse(message, HttpURLConnection.HTTP_FORBIDDEN);
    }
}

private boolean checkLogin(String username, String password) {
    if (username.equals("admin") && password.equals("admin")) {
        return true;
    }
    return false;
}

private void sendErrorResponse(Message message, int responseCode) {
    Message outMessage = getOutMessage(message);
    outMessage.put(Message.RESPONSE_CODE, responseCode);

    // Set the response headers
    @SuppressWarnings("unchecked")
    Map<String, List<String>> responseHeaders = (Map<String, List<String>>) message
            .get(Message.PROTOCOL_HEADERS);

    if (responseHeaders != null) {
        responseHeaders.put("WWW-Authenticate", Arrays.asList(new String[] { "Basic realm=realm" }));
        responseHeaders.put("Content-Length", Arrays.asList(new String[] { "0" }));
    }
    message.getInterceptorChain().abort();
    try {
        getConduit(message).prepare(outMessage);
        close(outMessage);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private Message getOutMessage(Message inMessage) {
    Exchange exchange = inMessage.getExchange();
    Message outMessage = exchange.getOutMessage();
    if (outMessage == null) {
        Endpoint endpoint = exchange.get(Endpoint.class);
        outMessage = endpoint.getBinding().createMessage();
        exchange.setOutMessage(outMessage);
    }
    outMessage.putAll(inMessage);
    return outMessage;
}

private Conduit getConduit(Message inMessage) throws IOException {
    Exchange exchange = inMessage.getExchange();
    EndpointReferenceType target = exchange.get(EndpointReferenceType.class);
    Conduit conduit = exchange.getDestination().getBackChannel(inMessage, null, target);
    exchange.setConduit(conduit);
    return conduit;
}

private void close(Message outMessage) throws IOException {
    OutputStream os = outMessage.getContent(OutputStream.class);
    os.flush();
    os.close();
}

}

I'm fighting with this for few days now. Don't know what to google any more. Help is appreciated.

like image 391
Felix Avatar asked Jun 13 '13 07:06

Felix


2 Answers

I've found solution. I was missing the following line in MANIFEST.MF file in war project:

Dependencies: org.apache.cxf

Maven wasn't includint this line by himself so I had to find workaround. I found about that here. It says: When using annotations on your endpoints / handlers such as the Apache CXF ones (@InInterceptor, @GZIP, ...) remember to add the proper module dependency in your manifest. Otherwise your annotations are not picked up and added to the annotation index by JBoss Application Server 7, resulting in them being completely and silently ignored.

This is where I found out how to change MANIFEST.MF file.

In short, I added custom manifest file to my project and referenced it in pom.xml. Hope this helps someone.

like image 78
Felix Avatar answered Nov 10 '22 23:11

Felix


The answer provided by Felix is accurate. I managed to solve the problem using his instructions. Just for completion here is the maven config that lets you use your own MANIFEST.MF file placed in the META-INF folder.

       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
                </archive>
            </configuration>
        </plugin>

and here is the relevant content of the content of the MANIFEST.MF file I was using.

Manifest-Version: 1.0
Description: yourdescription
Dependencies: org.apache.ws.security,org.apache.cxf
like image 35
user1970128 Avatar answered Nov 10 '22 22:11

user1970128