Thursday, 16 December 2010

Securing GWT apps with Spring Security


In this tutorial we will see how to integrate GWT with Spring's security module, i.e. Spring Security. We will see how to protect the GWT entrypoint, how to retrieve the user's credentials and how to log the various authentication events. Moreover, we are going to implement a custom authentication provider so that existing authentication schemes can be reused.

If you are a regular JavaCodeGeeks reader, you should probably know by now that we are really fond of GWT. In the past, Justin has written some killer articles on GWT: how to integrate GWT with Spring and Hibernate (JPA) and how to add Eclipse and Maven in the mix. Moreover, I have written about how to add JSON capabilities into your GWT application, how to add CAPTCHA for GWT and how to get started with SmartGWT. Finally, Pat has written about building your own GWT Spring Maven Archetype and integrating GWT, EJB3, Maven and JBoss.

Thus, it should be of no surprise that we are now bringing Spring's Security module into play. As the official site states, Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is the evolution of the Acegi framework which used Spring under the hood in order to provide security mainly to web applications. However, Spring Security is now a full-blown security framework, incorporating functionality not only for the web, but also for LDAP integration and ACLs creation. Before getting started with this tutorial, it would be nice to take a look at the Spring Security Reference Documentation and having at hand the Spring Security API Javadocs.

For this tutorial I will be using GWT 2.1.0 and Spring Security 3.0.5. You can download the latest production release here. As you might have guessed, some libraries from the core Spring framework will also be needed. You can download the framework here.

Let's get started by creating a new Web Application project in Eclipse (I suppose you have already installed the Google plugin for Eclipse and that you also have GWT deployed). I chose the profound name “GwtSpringSecurityProject” for the project's name. Here what the Eclipse screen will look like:



The first step for adding Spring security to our project is declaring a filter in our “web.xml” file. This filter, which is an instance of the FilterChainProxy class, will intercept all incoming requests and delegate the request's control to the appropriate Spring handler. The relevant web declaration file snippet is the following:

…
<filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
</filter-mapping>
...

We also have to define a ContextLoaderListener in our “web.xml” in order to bootstrap the Spring context. This is done via the following snippet:

…
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
...

Next we create a file named “applicationContext.xml” inside the “war/WEB-INF” folder. There we declare the spring security related information. The most important element is the “http”, which can be used to define on which URLs should security be applied, as well as what roles should the users have in order to access particular resources. In our case, the snippet is the following:

…
<http auto-config="true">
        <intercept-url pattern="/gwtspringsecurityproject/**" access="ROLE_USER"/>
        <intercept-url pattern="/gwt/**" access="ROLE_USER"/>
        <intercept-url pattern="/**/*.html" access="ROLE_USER"/>
        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
</http>
...

In short, the above states that role “ROLE_USER” is required in order to gain access to the files under the “gwt” and the “gwtspringsecurityproject” folders (where the GWT related resources reside). Similarly, all HTML files (like GWT's entrypoint) require the same role. The “IS_AUTHENTICATED_ANONYMOUSLY” means that all users can access the particular resource, without having to be part of a specific role. With this simple usage of the “http” element, the default login page and logout URL will be used by Spring.

All the authentication requests are handled by an AuthenticationManager, so an instance of that has to be declare in our file. More specifically, the requests are usually delegated to an AuthenticationProvider. Some already created implementations can be used, such as the DaoAuthenticationProvider (when working with roles and users defined in a DB) or the LdapAuthenticationProvider (which authenticates users against an LDAP server). For the purposes of this tutorial however, we are going to create a custom authentication provider and integrate it with spring's security infrastructure.

Before we delve into the application's code, we have to take care of dependencies first. Here are the JARs that have to be added to the project's classpath:
  • org.springframework.context-3.0.5.RELEASE.jar
  • spring-security-core-3.0.5.RELEASE.jar
  • spring-security-web-3.0.5.RELEASE.jar

Ok, now we are ready. Our provider is quite plain and just uses a static Map in order to store users and their corresponding password. Here is the code:

package com.javacodegeeks.gwt.security.server.auth;

import java.util.HashMap;
import java.util.Map;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class CustomAuthenticationProvider implements AuthenticationProvider {
    
    private static Map<String, String> users = new HashMap<String, String>();
    
    static {
        users.put("fabrizio", "javacodegeeks");
        users.put("justin", "javacodegeeks");
    }

    @Override
    public Authentication authenticate(Authentication authentication) 
            throws AuthenticationException {
        
        String username = (String) authentication.getPrincipal();
        String password = (String)authentication.getCredentials();
        
        if (users.get(username)==null)
            throw new UsernameNotFoundException("User not found");
        
        String storedPass = users.get(username);
        
        if (!storedPass.equals(password))
            throw new BadCredentialsException("Invalid password");
        
        Authentication customAuthentication = 
            new CustomUserAuthentication("ROLE_USER", authentication);
        customAuthentication.setAuthenticated(true);
        
        return customAuthentication;
        
    }

    @Override
    public boolean supports(Class<? extends Object> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

Let's begin the elaboration on that code from the end. The supports method defines the kind of authentication that this provider provides. In our case, the UsernamePasswordAuthenticationToken is the one we wish to handle. That implementation is designed for simple presentation of a username and password.

The authenticate method is implemented and inside that we retrieve the username provided in the login form (via the getPrincipal method) as well as the accompanying password (via the getCredentials method). First, we check if the specific username exists and if not, a UsernameNotFoundException is thrown. Similarly, if the username exists but the password is incorrect, a BadCredentialsException is thrown. Note that both theses exceptions extend the parent AuthenticationException class.

If both the username and the password are correct, we are in place to authenticate the user. In order to do so, we have to return a concrete instance of the Authentication interface. In that, we have to encapsulate the already known user information (credentials etc.) as well as the roles (authorities) that the user has. Note that the assigned role (ROLE_USER) matches the one declared in the “applicationContext.xml” file. In addition, the setAuthenticated method has to be invoked (with true as argument) in order to indicate to the rest of the authentication chain that the specific user was successfully authenticated by our module. Let's see how the custom authentication object is defined in our case:

package com.javacodegeeks.gwt.security.server.auth;

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;

public class CustomUserAuthentication implements Authentication {
    
    private static final long serialVersionUID = -3091441742758356129L;
    
    private boolean authenticated;
    
    private GrantedAuthority grantedAuthority;
    private Authentication authentication;
    
    public CustomUserAuthentication(String role, Authentication authentication) {
        this.grantedAuthority = new GrantedAuthorityImpl(role);
        this.authentication = authentication;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(grantedAuthority);
        return authorities;
    }

    @Override
    public Object getCredentials() {
        return authentication.getCredentials();
    }

    @Override
    public Object getDetails() {
        return authentication.getDetails();
    }

    @Override
    public Object getPrincipal() {
        return authentication.getPrincipal();
    }

    @Override
    public boolean isAuthenticated() {
        return authenticated;
    }

    @Override
    public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
        this.authenticated = authenticated;
    }

    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

}

In the constructor, we pass the user's role and the original Authentication object. In the implemented methods, the most important one is the getAuthorities, which returns the authorities that the principal has been granted. That information is provided inside a collection of GrantedAuthority objects.

Let's see now how the “applicationContext.xml” looks like:

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <beans:bean id="customAuthListener" class="com.javacodegeeks.gwt.security.server.auth.CustomAuthListener"/>

    <http auto-config="true">
        <intercept-url pattern="/gwtspringsecurityproject/**" access="ROLE_USER"/>
        <intercept-url pattern="/gwt/**" access="ROLE_USER"/>
        <intercept-url pattern="/**/*.html" access="ROLE_USER"/>
        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    </http>
    
    <beans:bean id="customAuthenticationProvider" class="com.javacodegeeks.gwt.security.server.auth.CustomAuthenticationProvider" />    
    
    <authentication-manager alias="authenticationManager">
     <authentication-provider ref="customAuthenticationProvider"/>
 </authentication-manager>
        
</beans:beans>

Every element of the declaration file has been defined except for the “CustomAuthListener”. Being part of the Spring framework, Spring Security allows the application developer to provide callbacks which will be invoked on specific parts of the application's lifecycle. Thus, we can register our methods to be called when specific authentication events occur. In our case, we will create a listener that receives AbstractAuthorizationEvents, i.e. all security interception related events. Let's see how this is accomplished:

package com.javacodegeeks.gwt.security.server.auth;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;

public class CustomAuthListener implements ApplicationListener<AbstractAuthenticationEvent> {
 
 private static final Log logger = LogFactory.getLog(CustomAuthListener.class);

 @Override
 public void onApplicationEvent(AbstractAuthenticationEvent event) {
  
 final StringBuilder builder = new StringBuilder();
        builder.append("Authentication event ");
        builder.append(event.getClass().getSimpleName());
        builder.append(": ");
        builder.append(event.getAuthentication().getName());
        builder.append("; details: ");
        builder.append(event.getAuthentication().getDetails());

        if (event instanceof AbstractAuthenticationFailureEvent) {
            builder.append("; exception: ");
            builder.append(((AbstractAuthenticationFailureEvent) event).getException().getMessage());
        }

        logger.warn(builder.toString());

 }

}

In our implementation, we just log all successful and unsuccessful authentication events (based on the LoggerListener class) but it is obviously quite straightforward to provide your own business logic here.

Finally, we will create a GWT asynchronous server side service that will provide the client with information regarding the user and the username that he has logged in with. If you have the tiniest experience with GWT, you will not have any problems understanding the code. Here are the two interfaces and the concrete implementation of the service:

AuthService

package com.javacodegeeks.gwt.security.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("auth")
public interface AuthService extends RemoteService {
 String retrieveUsername();
}

AuthServiceAsync

package com.javacodegeeks.gwt.security.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * The async counterpart of <code>AuthService</code>.
 */
public interface AuthServiceAsync {
 void retrieveUsername(AsyncCallback<String> callback);
}

AuthServiceImpl

package com.javacodegeeks.gwt.security.server;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.javacodegeeks.gwt.security.client.AuthService;

@SuppressWarnings("serial")
public class AuthServiceImpl extends RemoteServiceServlet implements AuthService {

    @Override
    public String retrieveUsername() {
        
        Authentication authentication =
            SecurityContextHolder.getContext().getAuthentication();
        
        if (authentication==null){
            System.out.println("Not logged in");
            return null;
        }
        else {
            return (String) authentication.getPrincipal();
        }
        
    }
    
}

The code is very simple. We use the SecurityContextHolder class to retrieve the current SecurityContext and then the getAuthentication method in order to take reference of the underlying Authentication object. From that, we retrieve the username, if any, via the getPrincipal method.

Of course, we have to declare the specific servlet in our application “web.xml” file. Here it is:

... 
<servlet>
 <servlet-name>authServlet</servlet-name>
 <servlet-class>com.javacodegeeks.gwt.security.server.AuthServiceImpl</servlet-class>
</servlet>

<servlet-mapping>
 <servlet-name>authServlet</servlet-name>
 <url-pattern>/gwtspringsecurityproject/auth</url-pattern>
</servlet-mapping>
...

And here is the whole web declaration file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
     
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Servlets -->
    <servlet>
        <servlet-name>greetServlet</servlet-name>
        <servlet-class>
            com.javacodegeeks.gwt.security.server.GreetingServiceImpl
        </servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>greetServlet</servlet-name>
        <url-pattern>/gwtspringsecurityproject/greet</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>authServlet</servlet-name>
        <servlet-class>com.javacodegeeks.gwt.security.server.AuthServiceImpl</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>authServlet</servlet-name>
        <url-pattern>/gwtspringsecurityproject/auth</url-pattern>
    </servlet-mapping>

    <!-- Default page to serve -->
    <welcome-file-list>
        <welcome-file>GwtSpringSecurityProject.html</welcome-file>
    </welcome-file-list>

</web-app>

Let's see how this service is used inside the application's entry point. We add the following code snippet just before the end of the onModuleLoad method:

authService.retrieveUsername(
 new AsyncCallback<String>() {
  public void onFailure(Throwable caught) {
   dialogBox.setText("Remote Procedure Call - Failure");
  }
  public void onSuccess(String result) {
   nameField.setText(result);
  }
 }
);

A last step before launching our application is to take care of the runtime dependencies. Spring requires a bunch of libraries in order to do its DI magic, so here is the list of the JARs that have to be present inside your “war/WEB-INF/lib” folder:
  • org.springframework.aop-3.0.5.RELEASE.jar
  • org.springframework.asm-3.0.5.RELEASE.jar
  • org.springframework.beans-3.0.5.RELEASE.jar
  • org.springframework.context-3.0.5.RELEASE.jar
  • org.springframework.core-3.0.5.RELEASE.jar
  • org.springframework.expression-3.0.5.RELEASE.jar
  • org.springframework.web-3.0.5.RELEASE.jar
  • spring-security-config-3.0.5.RELEASE.jar
  • spring-security-core-3.0.5.RELEASE.jar
  • spring-security-web-3.0.5.RELEASE.jar

After copying all of the above, launch the Eclipse project configuration and try to access the default URL:

http://127.0.0.1:8888/GwtSpringSecurityProject.html?gwt.codesvr=127.0.0.1:9997


The request will be intercepted by Spring Security and you will be presented with a default login page. Provide the valid credentials as below:



Submit the form data and you will be redirected to the original URL. Notice that the text field will be populated with the username used to log in.



Return to your Eclipse Console view and check out the various logs printed there. You should see something like the following:


12 Dec 2010 8:45:49 PM com.javacodegeeks.gwt.security.server.auth.CustomAuthListener onApplicationEvent
WARNING: Authentication event AuthenticationSuccessEvent: CustomUserAuthentication; details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffdaa08: RemoteIpAddress: 127.0.0.1; SessionId: im1fdjvdu7yw
12 Dec 2010 8:45:49 PM com.javacodegeeks.gwt.security.server.auth.CustomAuthListener onApplicationEvent
WARNING: Authentication event InteractiveAuthenticationSuccessEvent: CustomUserAuthentication; details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffdaa08: RemoteIpAddress: 127.0.0.1; SessionId: im1fdjvdu7yw


That's all folks. You can find here the Eclipse project created. Have fun!

Related Articles :



19 comments:

  1. Nice tutorial, let me add that if you need advanced tracking of login, logout and session end you can use Spring Application Events:

    Example:

    package com.tecsisa.server.security;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.security.context.SecurityContext;
    import org.springframework.security.event.authentication.InteractiveAuthenticationSuccessEvent;
    import org.springframework.security.event.authentication.AuthenticationFailureBadCredentialsEvent;
    import org.springframework.security.ui.WebAuthenticationDetails;
    import org.springframework.security.ui.session.HttpSessionDestroyedEvent;

    public class AutenticationEventListener implements ApplicationListener {
    public void onApplicationEvent(ApplicationEvent event) {
    //Session ends
    if (event instanceof HttpSessionDestroyedEvent){
    String username ="";
    String remoteAddress=null;
    HttpSessionDestroyedEvent logoutEvent = (HttpSessionDestroyedEvent) event;
    SecurityContext securityContext = (SecurityContext) logoutEvent.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
    if (securityContext!=null){
    username = (String) logoutEvent.getSession().getAttribute("SPRING_SECURITY_LAST_USERNAME");
    WebAuthenticationDetails webAuthenticationDetails = (WebAuthenticationDetails) securityContext.getAuthentication().getDetails();
    if (webAuthenticationDetails!=null){
    remoteAddress = webAuthenticationDetails.getRemoteAddress();
    }
    //Log action
    }
    return;
    }
    //Success
    if (event instanceof InteractiveAuthenticationSuccessEvent) {
    InteractiveAuthenticationSuccessEvent successEvent = (InteractiveAuthenticationSuccessEvent) event;
    WebAuthenticationDetails webAuthenticationDetails = (WebAuthenticationDetails) successEvent.getAuthentication().getDetails();
    String username = successEvent.getAuthentication().getName();
    //Log action
    return;
    }
    //Bad credentials
    if (event instanceof AuthenticationFailureBadCredentialsEvent){
    AuthenticationFailureBadCredentialsEvent failureEvent = (AuthenticationFailureBadCredentialsEvent) event;
    WebAuthenticationDetails webAuthenticationDetails = (WebAuthenticationDetails) failureEvent.getAuthentication().getDetails();
    String username = failureEvent.getAuthentication().getName();
    //Log action
    return;
    }
    }
    }

    Regards,
    Javier Ruiz,
    Tecsisa
    http://www.tecsisa.com

    ReplyDelete
  2. Hi. This is nice of course... but this is basic and not enough. Things become difficult when you try to deal with session expiration, authorization (not simply allow/deny URL, but separate RPC methods with specific access logic), etc... There are answers for all this and I had to look/invent them to achieve complex solution.
    Would be nice if you continue this with more real examples.

    Best regards,
    Vitaliy 'Talik' Semeshko

    ReplyDelete
  3. @Tecsisa
    Yes of course, you are absolutely right. Thanx for the additional info!

    @Vitaliy
    You are totally right, this is just a getting started guide to let someone quickly set up a basic infrastructure. It would be impractical to try to demonstrate all the Spring Security framework capabilities in just one post. More advanced functionality will most probably presented by me or Justin on later posts. Stay tuned! :-)

    ReplyDelete
  4. Excellent tutorial, thanks.

    ReplyDelete
  5. I have been having a 3 days nightmare trying to replace the built-in login page with my own jsp login page. I have went over countless tutorials and I can't get it to work no matter what. I always end up with the same error:
    Failed to load source for: http://127.0.0.1:8888/j_spring_security_check

    Does anyone have any idea or even better, has anyone been able to replace the login page?

    ReplyDelete
  6. Hi Detra,

    Can't really figure out what the problem is from just that line. Is there an exception you are getting?

    In general, if you wish to provide a custom login page, you have to add a "form-login" element inside your element of the applicationContext.xml. Please check the Spring Security documentation on how to do that.

    Regards,
    Fabrizio

    ReplyDelete
  7. Great post Fabrizio! Clear and concise.

    I need to authenticate the user against a hibernate datasource. How would I go about this. An example would be highly appreciated.

    ReplyDelete
  8. Hi kibyegon,

    Thank you for your support.

    I guess you could use a custom implementation of the Spring Security UserDetailsService interface.

    Take a look at the following links and let me know how it goes:

    http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html

    http://www.codercorp.com/blog/spring/security-spring/writing-custom-userdetailsservice-for-spring-security.html

    Regards,
    Fabrizio

    ReplyDelete
  9. I've created two modules
    1) GWTAppAuth
    2) GWTApp
    when I'm try posting form from GWTAppAuth to j_spring_security_check nothing happened
    Firebug shows in console Failed to load source for: http://127.0.0.1:8888/j_spring_security_check
    But if I try after that manually access to GWTApp it works
    Anybody knows what a matter?
    Seems SpringSecurity just doesn't redirect to another module

    ReplyDelete
  10. Hi Andriy,

    Spring Security has no knowledge of GWT Modules, so the problem is not GWT specific.

    Please make sure that the Intercept-URL patterns are correctly defined in your application.

    Also check that the Form-Login URL is indeed j_spring_security_check (can you POST data to that URL?).

    Finally, you can always go back to the reference documentation:

    http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html

    Cheers

    ReplyDelete
  11. Hi Fabrizio
    Looks like Spring Security just doesn't redirect to second(GWTApp).
    How do I check it?
    1) Run application in hosted mode
    2) try to access to GWTApp.html
    3) Spring security redirects me to GWTAppAuth.html
    4)press login button
    In this place if we check firebug log we can see
    POST http://127.0.0.1:8888/j_spring_security_check
    and responce - Failed to load source for: http://127.0.0.1:8888/j_spring_security_check
    then next record - GET http://127.0.0.1:8888/GWT/GWTApp.html?gwt.codesvr=127.0.0.1:9997
    and fetching all needed resources
    Now I can manually input http://127.0.0.1:8888/GWT/GWTApp.html and give me access to GWTApp.html

    ReplyDelete
  12. Hi all,I have followed the tutorial but I have a problem in my spring application, I want to deploy it on tomcat6 the application is successfully deployed in tomcat6 server but it is giving error-
    FAIL - Application at context path could not be started
    how can i solve this problem.

    ReplyDelete
  13. Hi,
    I followed this tutorial but while running in hosted mode I had this exception:
    DEBUG o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
    org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:71) ~[spring-security-core-3.1.0.RC2.jar:3.1.0.RC2]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:204) ~[spring-security-core-3.1.0.RC2.jar:3.1.0.RC2]

    and the result is that there's no redirection to the default login page but it loads the default html page.
    My intercept-rules are the same you have in your applicationContext.xml

    Any idea??

    Regards

    ReplyDelete
  14. Dear Fabrizio,

    I'm a total noob when it comes to Spring framework. If you have the time would you mind teaching me one-on-one in #javacodegeeks@irc.freenode.net ? I ran this tutorial app but have no clue even to the basic stuff, such as where in the source code did you even write out the string "Login with Username and Password"?

    Regards,

    ReplyDelete
  15. Hey guys,

    In case you are running into problems with this tutorial, please check that you are using the correct lib versions (e.g. Spring Security 3.0.5 etc.).

    Additionally, at the end of the tutorial, we provide the whole eclipse project. You can download it and play with it so that you better understand what is going on.

    @Mario
    Yeah, that was tricky. This refers to the default login page provided by Spring security. :-)

    Cheers,
    Ilias

    ReplyDelete
  16. Hello!

    I imported your source code, and added jar files (Java Build Path - Libraries) as stated above. All versions are 3.0.5 . Still, when I try to run the project as Web application, I get an error:

    SEVERE: Context initialization failed
    org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/security]
    Offending resource: ServletContext resource [/WEB-INF/applicationContext.xml]

    Is there any suggestion to solve this?

    Many thanks.

    ReplyDelete
  17. Hi Dabar,

    You have probably created the applicationContext.xml file in a wrong way. Make sure that the correct namespace declarations have been made, e.g. look in the beans:beans section. Compare your with the one provided in the article to be sure.

    Regards,
    Ilias

    ReplyDelete
  18. Thanks for the tutorial, it got me going on adding security to my GWT project.

    However, the most interesting questions are not on the Spring side, but on the GWT side. I have an application that is partly public, without any security and partly secure. I still have two issues to resolve.

    1. I can define services as secure or public, no problem. But what if I want only certain service methods to be secure instead of an entire service? Or assign different roles to service methods?

    2. As soon as I go from the public part to the secure part of my web site, how do I deal with that? I would hate to litter my GUI with checks whether it is secure or not and demand the user to login when he enters a secure part. Instead, I would like the login to be triggered whenever a secure service is called and the user is not logged in. The standard solution for a redirect is inadequate for that, since you would leave the GWT app and lose state.

    I am currently thinking about not redirecting to the login page, but simply returning a 403 from the security filter when a secure service method is called and the user is not logged in. But then the service request would fail and the user would have to redo his last action. That is not user friendly.

    ReplyDelete
  19. fadi al-katout2 March 2012 11:43

    Hi,

    am using this tutorial and it works fine in dev. mode (from eclipse) but when I compile and deploy the project I get a blanck screen instead of the login form! can u please help me?

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...