user3157090
user3157090

Reputation: 537

Jersey webservice basic authetication is not asking for username and password

I have implemented the jersey webservice and trying to authenticate the webservice by asking for username and password when some one calls the webservice from the browser. I am not sure what i am missing from below code, when some one calls the webservice URL, it is not asking for credentials, it is directly comming to AuthFilter class below. Please help to find the issue. Here is the code below. I have also added the CXF authentication which i used earlier, i am trying to implement now with jersey.

AuthFilter class

package com.myProj.inventory.ws.rest.v1.security;

import java.util.Set;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import com.myProj.commons.user.model.DetailedUser;
import com.myProj.commons.user.service.UserInfoService;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;

@Component
public class AuthFilter implements ContainerRequestFilter {

    private static Logger logger = Logger.getLogger(AuthenticationFilter.class);

    private static final String RIGHT_INVOKE_WEBSERVICE = "INVOKE_WEBSERVICE";

    @Autowired
    private UserInfoService userInfoService;

    @Override
    public ContainerRequest filter(ContainerRequest containerRequest)
            throws WebApplicationException {

        // Get the authentification passed in HTTP headers parameters
        String auth = containerRequest.getHeaderValue("authorization");

        // If the user does not have the right (does not provide any HTTP Basic
        // Auth)
        if (auth == null) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }

        // lap : loginAndPassword
        String[] lap = BasicAuth.decode(auth);

        // If login or password fail
        if (lap == null || lap.length != 2) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }

        try {
            boolean isRightExists = false;
            // DO YOUR DATABASE CHECK HERE (replace that line behind)...
            DetailedUser detailedUser = userInfoService.readUserInfoAsUser(
                    lap[0], lap[1]);

            if (detailedUser != null) {
                Set<String> rights = detailedUser.getRights();

                for (String right : rights) {
                    // TODO: We have additional rights to check
                    if (RIGHT_INVOKE_WEBSERVICE.equalsIgnoreCase(right)) {
                        isRightExists = true;
                    }
                }
            }

            if (!isRightExists) {
                throw new WebApplicationException(Status.UNAUTHORIZED);
            }

        } catch (AuthenticationException ae) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }

        return containerRequest;
    }
}

Credentials Decoding class

package com.myProj.inventory.ws.rest.v1.security;

import javax.xml.bind.DatatypeConverter;

public class BasicAuth {
    /**
     * Decode the basic auth and convert it to array login/password
     * @param auth The string encoded authentification
     * @return The login (case 0), the password (case 1)
     */
    public static String[] decode(String auth) {
        //Replacing "Basic THE_BASE_64" to "THE_BASE_64" directly
        auth = auth.replaceFirst("[B|b]asic ", "");

        //Decode the Base64 into byte[]
        byte[] decodedBytes = DatatypeConverter.parseBase64Binary(auth);

        //If the decode fails in any case
        if(decodedBytes == null || decodedBytes.length == 0){
            return null;
        }

        //Now we can convert the byte[] into a splitted array :
        //  - the first one is login,
        //  - the second one password
        return new String(decodedBytes).split(":", 2);
    }
}

Web.xml jersey servlet mapping

<servlet>
    <servlet-name>restwebservice</servlet-name>
    <servlet-class>
        com.sun.jersey.spi.spring.container.servlet.SpringServlet
    </servlet-class>
    <init-param>

    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    <param-value>com.sun.jersey.api.container.filter.LoggingFilter;com.guthyrenker.inventory.ws.rest.v1.security.AuthFilter</param-value>
    </init-param>
    <init-param>
        <param-name>
            com.sun.jersey.config.property.packages
         </param-name>

        <param-value>com.guthyrenker.inventory.ws.rest.v1.service</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>restwebservice</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

CXF basic authentication

public class AuthenticationFilter implements RequestHandler { private static Logger logger = Logger.getLogger(AuthenticationFilter.class);

private static final String RIGHT_INVOKE_WEBSERVICE = "INVOKE_WEBSERVICE";

@Autowired
private UserInfoService userInfoService;

public Response handleRequest(Message request, ClassResourceInfo resourceClass) {

    AuthorizationPolicy policy = (AuthorizationPolicy) request.get(AuthorizationPolicy.class);
    if (policy == null) {
        // issue an authentication challenge to give invoker a chance to reply with credentials
        // (this is useful if web service is being called from a browser)
        return Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic").build();
    }

    // check authorization realm - we currently only support Basic authentication
    String realm = policy.getAuthorizationType();
    if (!"Basic".equalsIgnoreCase(realm)) {
        return Response.status(Status.UNAUTHORIZED).header("WWW-Authenticate", "Basic").build();
    }

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

    try {
        boolean isRightExists = false;

        DetailedUser detailedUser = userInfoService.readUserInfoAsUser(username, password);

        if (detailedUser != null) {
            Set<String> rights = detailedUser.getRights();

            for (String right : rights) {
                //TODO: We have additional rights to check
                if (RIGHT_INVOKE_WEBSERVICE.equalsIgnoreCase(right)) {
                    isRightExists = true;
                }
            }
        }

        if (!isRightExists) {
            return ErrorFactory.newFault(CommonError.ACCESS_DENIED);
        }

    } catch (AuthenticationException ae) {
        return ErrorFactory.newFault(CommonError.AUTHENTICATION_FAILED);
    }

    return null;
}

Upvotes: 1

Views: 985

Answers (2)

jansohn
jansohn

Reputation: 2346

For anyone still looking for a solution, here is how I solved it:

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
    String authorization = ((ContainerRequest) requestContext.getRequest()).getHeaderString(HttpHeaders.AUTHORIZATION);

    if (authorization == null) {
        final ResponseBuilder builder = Response.status(Response.Status.UNAUTHORIZED)
                .header(HttpHeaders.WWW_AUTHENTICATE, "Basic");
        requestContext.abortWith(builder.build());
        return;
    }

    // continue with authentication
}

Upvotes: 0

Juned Ahsan
Juned Ahsan

Reputation: 68715

You seems to be confused between Basic and Form authentication. Basic auhtentication works using headers while Form authentication presents the login form. Basic authentication works on the basis of below mentioned header:

WWW-Authenticate

Upvotes: 0

Related Questions