Thursday, April 4, 2013

Annotation Based Security in Wicket :


Annotation Based Security:

1.) Create an enum class to define the roles:

public enum Role {

      USER, SUPP, ADMIN;

}

2.) Create an annotation interface which will accept the role and actions:

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Inherited

public @interface Authorization {

 

      Role role();

      AuthActions[] actions();

      public enum AuthActions{

            READ,WRITE;

      }

}

3.) Create an annotation interface which will accept the authorization values:

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Inherited

public @interface Authorizations {

      Authorization[] values();

}

4.) Create annotation interface for write authorization:

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Inherited

public @interface WriteAuthorization {

 

}

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Inherited

public @interface WriteAuthorization {

 

}

 

5.) Create sample VO class which will accept the user  credentials :

import java.io.Serializable;

 

 

public class User implements Serializable{

 

      private static final long serialVersionUID = 1L;

 

      private String userId;

      private String userName;

      public String getUserId() {

            return userId;

      }

      public void setUserId(String userId) {

            this.userId = userId;

      }

      public String getUserName() {

            return userName;

      }

      public void setUserName(String userName) {

            this.userName = userName;

      }

     

}

6.) Create a class which store the user details and his roles, this class will be used by filter:

import java.io.Serializable;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

 

public class TestUser implements Serializable {

 

      /**

       *

       */

      private static final long serialVersionUID = 1L;

      private final List<Role> roles;

      private final User user;

       public TestUser(final List<String> inRoles, final User inUser) {

              final ArrayList<Role> tmpRoles = new ArrayList<Role>();

              if (inRoles != null) {

                  for (String name : inRoles) {

                      for (Role userRole : Role.values()) {

                          if (name.equals(userRole.name())) {

                              tmpRoles.add(userRole);

                          }

                      }

                  }

              }

              roles = Collections.unmodifiableList(tmpRoles);

              user = inUser;

          }

       public final boolean hasRole(final Role inRole) {

              for (Role role : roles) {

                  if (role == inRole) {

                      return true;

                  }

              }

              return false;

          }

      public List<Role> getRoles() {

            return roles;

      }

 

      public User getUser() {

            return user;

      }

 

}

ThreadLocal:


7.) Create UserSession class, here we need to save the user and roles in ThreadLocal:

import java.util.List;

 

public class UserSession {

 

      private static final ThreadLocal<User> currentUser=new ThreadLocal<User>();

      private static final ThreadLocal<List<String>> roles=new ThreadLocal<List<String>>();

     

      public static User getCurrentuser() {

            return currentUser.get();

      }

      public static List<String> getRoles() {

            return roles.get();

      }

     

      public static void setCurrentUser(User user, List<String> inRoles) {

            currentUser.set(user);

            roles.set(inRoles);

      }

     

      public static void cleanup() {

            currentUser.set(null);

            roles.set(null);

     

      }

}

 

8.) Next you’ll need to provide your custom session class-making it a subclass of AuthenticatedWebSession. This class requires you to override the following methods:

  • authenticate - called when the user needs to be authenticated using a username and password
  • getRoles - called after the users was authenticated and should provide the roles associated with the authenticated user.

import java.util.Locale;

import org.apache.wicket.Request;

import org.apache.wicket.authentication.AuthenticatedWebSession;

import org.apache.wicket.authorization.strategies.role.Roles;

 

public class TestSession extends AuthenticatedWebSession{

      /**

       *

       */

      private static final long serialVersionUID = 1L;

     

      private final TestUser user;

      public TestSession(Request request) {

            super(request);

            user = new TestUser(UserSession.getRoles(),  UserSession.getCurrentuser());

        setLocale(Locale.ENGLISH);

      }

      public TestUser getUser() {

            return user;

      }

      @Override

      public boolean authenticate(String userId, String userName) {

            return false;

      }

      @Override

      public Roles getRoles() {

            Roles roles=new Roles();

            roles.add("USER");

            return roles;

      }

 

}

9.) Create a filter UserFilter .java class which extends the OncePerRequestFilter. This class should authenticate the panex user and set user details in UserSession.

final IPanexProfile profile=(IPanexProfile)securityContext.getProfile();

                  String name=profile.getUniqueName ();

                  String userId=profile.getUserId ();

List<String> roles = new ArrayList<String>();

            roles.add(Role.ADMIN.name());

            roles.add(Role.SUPP.name());

            User user=new User();

            user.setUserId(userId);

            user.setUserName(name);

            UserSession.setCurrentUser(user, roles);

10.) Enabling the annotations for role based authorization is done by setting the WebApplication#getSecuritySettings value to AuthorizationStrategy class. This class implements the IAuthorizationStrategy and IUnauthorizedComponentInstantiationListener interfaces.

This class have a method isAuthorized() which will read the annotation values of each classes and check whether the user have the permission to access this page.

private boolean isAuthorized(

                  final Class<? extends Component> componentClass,

                  final AuthActions inRequiredAuth) {

            final TestSession session = (TestSession) TestSession.get();

            final TestUser loginUser = session.getUser();

 

            final Authorizations authorizations = componentClass

                        .getAnnotation(Authorizations.class);

            if (authorizations == null) {

           

                  return true;

            } else {

                  final Authorization[] auth = authorizations.values();

           

                  for (Authorization authorization : auth) {

                        if (loginUser.hasRole(authorization.role())) {

                              for (AuthActions action : authorization.actions()) {

                                    if (action == inRequiredAuth) {

 

                                          return true;

                                    }

                              }

                        }

                  }

                  return false;

            }

      }

 

To establish authorization and authentication, the application class must extend AuthenticatedWebApplication. When you create your class you’ll be asked to override the following methods:

  • newSession - return a subclass of AuthenticatedWebSession
  • getSignInPageClass - return the class for your login page (this one should not require authentication, otherwise you’ll create an infinite loop)

 In init() method of wicket application we need to set SecuritySettings value to AuthorizationStrategy class

 @Override

      protected void init() {

     

            getPageSettings().setAutomaticMultiWindowSupport(true);

        getMarkupSettings().setStripWicketTags(true);

        final AuthorizationStrategy authorizationStrategy = new AuthorizationStrategy();

       

        getSecuritySettings().setAuthorizationStrategy(authorizationStrategy);

        getSecuritySettings().setUnauthorizedComponentInstantiationListener(authorizationStrategy);

        addComponentInstantiationListener(new SpringComponentInjector(this));

        getResourceSettings().setThrowExceptionOnMissingResource(true);

      }

 

The authorization and role can be given to each page in the following way

 

@Authorizations(values = { @Authorization(actions = {AuthActions.READ}, role = Role.SUPP) })

public class FirstWicketHome extends WebPage()

 

FirstWicketHome page can be viewed only by the user who has the SUPP roles.

Web.xml :

You have to configure the filter in web.xml :

    <filter>

        <filter-name>userFilter</filter-name>

 <filter-class>test.security.ResourceIgnoringDelegatingFilter</filter-class>

            <init-param>

                  <param-name>DELEGATE_FILTER_CLASS</param-name>

              <param-value>test.security.UserFilter</param-value>

          </init-param>

    </filter><!--

<filter-mapping>

        <filter-name>userFilter</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

No comments:

Post a Comment