Reputation: 537
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.
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;
}
}
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);
}
}
<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>
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
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
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