How to Implement Basic Authentication with Glassfish

How to implement basic authentication with Glassfish?

You may try this guide: http://download.oracle.com/docs/cd/E19798-01/821-1750/beaxw/index.html I heard that web.xml sometimes not work properly. I had same problem but cannot test it now.

How do I get Basic Authentication, GlassFish, REST, and a single page application to all work together with my own login form?

Since posting this question I have found info on implementing a Servlet filter and using that to try to change the 401 response to a different status code. However, the filter never gains control if you have <auth-constraint> in your web.xml and the request is not authorized, so that did not help me. I still could not prevent the 401 responses.

But now I think I finally found the answer. I removed the <auth-constraint> tag from web.xml. I changed the Servlet filter to now extract the AUTHENTICATION_HEADER on its own and decode it (via javax.xml.bind.DatatypeConverter). Next I call HttpServletRequest.login (on the request object) with the decoded username and password. I catch the ServletException if the username/password combination is bad and use HttpServletResponse.sendError to send SC_FORBIDDEN. If I have a good login I call doFilter to continue on with processing of the request, and call HttpServletRequest.logout when it returns.

If I do this in combination with RolesAllowedDynamicFeature and annotations on the Jersey routines everything seems to work including calls to EJB's with their own security annotations.

Side note: before settling on HttpServletRequest.login I had tried to use HttpServletRequest.authenticate followed by checking the returned boolean, but when you gain control in that case the response has already been committed to be 401 and you cannot change it. I even tried passing a HttpServletResponseWrapper to authenticate to stop the commit from happening, but authenticate seems to get the response object through some other means, it seems to ignore the one you pass it (I even tried passed null and it didn't even notice).

Securing Glassfish REST Service with basic auth using annotations

You need to use the security-constraint element in web.xml descriptor in order to block specific resources and paths, and to specify the authorization constraints.

This doesn't mean that you can't add more fine-grained controls using Programmatic Security, as explained in Oracle's Java EE 6 Tutorial:

Programmatic security is embedded in an application and is used to make security decisions. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application.


As per your edited question.

I would use the security-constraint element for blocking the access to all non-registered users. This will force everybody to authenticate, so that your application knows the roles they have.
Then you can fine-grain control the access to the various resources using programmatic security.

With basic authentication I guess there are no other ways. If you want to avoid authentication for basic users, you need to go with form authentication and handle the authentication programmatically behind the scenes, authenticating them even if they aren't aware of, by using HttpServletRequest#login().

In both ways you should be able to setup rights in the way you have described. If you want to handle the unauthorized exception more smoothly, you'd better remove the @RolesAllowed annotation and instead use something like:

@GET
@Path("/{uuid}")
public Response getData(@PathParam("uuid") final String uuid, @Context SecurityContext sc) {
if (sc.isUserInRole("MyRole")) {
return result;
} else {
return notAllowedResult;
}
}

Basic Authentication in Glassfish

I'm not sure if defaults apply but you may need to create sun-web.xml and set a mapping for role "User":

<sun-web-app error-url="">
...
<security-role-mapping>
<role-name>User</role-name>
<group-name>filerealm-group-name</group-name>
</security-role-mapping>
...
</sun-web-app>

Basic Authentication on Glassfish using Ldap

In order to configure the realm in Glassfish look To Create an LDAP Realm in the GlassFish Server.

Regarding Apache Directory Studio, see Let's create an LDAP user and search for him. You may want to see Setting up an LDAP directory server for Alfresco development.

basic authentication fails with glassfish

The reason for the symptoms you encounter is that Oracle has enabled caching of HTTP responses by default with JDK7 in Web Start:

Caching enabled by default: Caching of network content for application
code running in Web Start mode is now enabled by default. This allows
application improved performance and consistency with applet execution
mode. To ensure the latest copy of content is used, the application
can use URLConnection.setUseCaches(false) or request header
Cache-Control values no-cache/no-store.

So what I did was, setting this header after creating the Jersey client:

Client client = Client.create();
client.addFilter( new HTTPBasicAuthFilter( userId, password ) );
client.addFilter( new ClientFilter() {

@Override
public ClientResponse handle( ClientRequest cr )
throws ClientHandlerException {
List<Object> cacheControlRequestValues = new ArrayList<Object>();
cacheControlRequestValues.add( "no-cache" );
cacheControlRequestValues.add( "no-store" );
cr.getHeaders().put( HttpHeaders.CACHE_CONTROL, cacheControlRequestValues );
return getNext().handle( cr );
}
}

Now if the above specification would be correct, and the implementation of Web Start would follow the HTTP/1.1 reference, which states

The purpose of the no-store directive is to prevent the inadvertent
release or retention of sensitive information (for example, on backup
tapes). The no-store directive applies to the entire message, and MAY
be sent either in a response or in a request. If sent in a request, a
cache MUST NOT store any part of either this request or any response
to it.

we would be fine - a network sniffer proved that the client was setting the Cache-Control header correctly. Also a ContainerResponseFilter of Jersey was showing me, that the header on the request was set correctly. The response on the other hand had no Cache-Control header set. Should not matter according to the specification, but in reality Web Start kept caching the responses!

So I wrote a ContainerResponseFilter that copies the Cache-Control header from the request to the response:

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

import javax.ws.rs.core.HttpHeaders;
import java.util.ArrayList;
import java.util.List;

public class CacheControlCopyFilter
implements ContainerResponseFilter

@Override
public ContainerResponse filter( ContainerRequest containerRequest, ContainerResponse containerResponse ) {
if ( containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ) != null ) {
List<Object> responseCacheControlValues = new ArrayList<Object>( containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ).size() );
for ( String value : containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ) ) {
responseCacheControlValues.add( value );
}
containerResponse.getHttpHeaders().put( HttpHeaders.CACHE_CONTROL, responseCacheControlValues );
}
return containerResponse;
}

}

and activated it in the web.xml

<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>my.package.CacheControlCopyFilter</param-value>
</init-param>

Then you have to delete your Java client cache:

"javaws -viewer" -> General
-> Settings...
-> Delete Files...
-> Select all three check boxes
-> OK

and voilà, no more annoying authentication pop ups :)



Related Topics



Leave a reply



Submit