Ej helt färdigställd roll och autentiseringshantering men all grundfunktionalitet finns. Saknar bekvämlighetsmetoder för att ställa in roller på enskilda komponenter, saknar helt SAML/Schibbolet-integration, saknar databas/entityrepresentation av roller.

git-svn-id: svn://svn.dsv.su.se/scipro/scipro/trunk@9 73ecded7-942e-4092-bab0-0e58ef0ee984
This commit is contained in:
mpeters 2011-01-21 17:52:02 +00:00
parent 93b9aa93ef
commit 0171b2d9ab
29 changed files with 571 additions and 46 deletions

@ -4,13 +4,16 @@ import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import se.su.dsv.scipro.basepages.BasePage;
import se.su.dsv.scipro.basepages.PublicPage;
import se.su.dsv.scipro.pages.EventPage;
import se.su.dsv.scipro.security.auth.Authorization;
/**
* @author Richard Wilkinson - richard.wilkinson@jweekend.com
* @author Martin Peters - mpeters@dsv.su.se
*
*/
public class HomePage extends WebPage {
public class HomePage extends PublicPage {
private static final long serialVersionUID = 1L;

@ -6,12 +6,16 @@ import org.apache.wicket.Page;
import org.apache.wicket.Request;
import org.apache.wicket.Response;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.strategies.CompoundAuthorizationStrategy;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import se.su.dsv.scipro.loginlogout.pages.LoginPage;
import se.su.dsv.scipro.loginlogout.pages.LogoutPage;
import se.su.dsv.scipro.pages.EventPage;
import se.su.dsv.scipro.security.auth.ComponentSecurityLogger;
import se.su.dsv.scipro.security.auth.MetaDataActionStrategy;
import se.su.dsv.scipro.security.auth.RoleBasedAuthorizationStrategy;
/**
* Application object for your web application. If you want to run this application without deploying, run the Start class.
@ -53,6 +57,13 @@ public class SciProApplication extends WebApplication {
mountBookmarkablePage("logout", LogoutPage.class);
addComponentInstantiationListener(getSpringInjector());
CompoundAuthorizationStrategy cas = new CompoundAuthorizationStrategy();
cas.add(new RoleBasedAuthorizationStrategy());
cas.add(new MetaDataActionStrategy());
getSecuritySettings().setAuthorizationStrategy(cas);
getSecuritySettings().setUnauthorizedComponentInstantiationListener(new ComponentSecurityLogger());
}

@ -1,5 +1,7 @@
package se.su.dsv.scipro;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.security.auth.login.FailedLoginException;
@ -15,9 +17,17 @@ import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.auth.Authenticator;
import se.su.dsv.scipro.data.dao.interfaces.UserDao;
import se.su.dsv.scipro.data.dataobjects.User;
import se.su.dsv.scipro.security.auth.Authenticator;
import se.su.dsv.scipro.security.auth.roles.Admin;
import se.su.dsv.scipro.security.auth.roles.DefaultRole;
import se.su.dsv.scipro.security.auth.roles.Employee;
import se.su.dsv.scipro.security.auth.roles.External;
import se.su.dsv.scipro.security.auth.roles.Role;
import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.security.auth.roles.Student;
import se.su.dsv.scipro.security.auth.roles.SysAdmin;
@ -30,7 +40,7 @@ public class SciProSession extends WebSession {
@SpringBean
private UserDao userDao;
//private List<Role> roles = new ArrayList<Role>();
private List<Role> roles = new ArrayList<Role>();
private User user = null;
private String loggedInIdentity = null;
@ -119,36 +129,39 @@ public class SciProSession extends WebSession {
/*
* Here we switch the logged in user to be that of the person chosen be the logged in admin
*/
/*
if(userDao.isAdmin(user) && loggedInAsUsername != null){
this.user = userDao.getUserByUserName(loggedInAsUsername);
this.user = userDao.getUserByUsername(loggedInAsUsername);
if( user == null)
throw new NullPointerException("No user with this username found in the database, despite successful authentication");
throw new NullPointerException("No user with this username found in the database, despite successful authentication");
}
if(userDao.isAuthor(user)){
rolesString = rolesString +"AUTHOR,";
roles.add(new AuthorRole());
if(userDao.isStudent(user)){
roles.add(new Student());
}
if(userDao.isSupervisor(user)){
rolesString = rolesString +"SUPERVISOR,";
roles.add(new SupervisorRole());
if(userDao.isExternal(user)){
roles.add(new External());
}
if(userDao.isEmployee(user)){
roles.add(new Employee());
}
if(userDao.isAdmin(user)){
rolesString = rolesString +"ADMIN,";
roles.add(new AdminRole());
roles.add(new Admin());
}
if(userDao.isSysadmin(user)){
roles.add(new SysAdmin());
}
if(roles.isEmpty()){
roles.add(new DefaultRole());
}
*/
Logger logger = Logger.getLogger("Application");
logger.log(Level.INFO, "User: "+getLoggedInIdentity()+ " logged in as: "+user.getFirstName()+" "+user.getLastName()+" "+user.getUserNames());
return true;
} catch (FailedLoginException e) {
//e.printStackTrace();
e.printStackTrace();
} catch (LoginException e) {
//e.printStackTrace();
e.printStackTrace();
}
return false;
}
@ -157,6 +170,13 @@ public class SciProSession extends WebSession {
public String toString(){
return loggedInIdentity;//+" Roles: "+rolesString;
}
public boolean authorizedForRole(Roles role) {
for(Role existingRole : roles){
if(existingRole.authorizedForRole(role))
return true;
}
return false;
}
}

@ -4,6 +4,10 @@ import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.WebPage;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles;
@Authorization(requiresLoggedInUser = true, authorizedRoles = {Roles.STUDENT, Roles.ADMIN, Roles.EMPLOYEE, Roles.EXTERNAL, Roles.SYSADMIN})
public abstract class BasePage extends WebPage {
public BasePage(){
@ -14,12 +18,9 @@ public abstract class BasePage extends WebPage {
super(pp);
}
public static String ADMIN_CSS = "admin";
public static String SUPERVISOR_CSS = "supervisor";
public static String AUTHOR_CSS = "author";
public static String GLOBAL_CSS = "global";
public static String POPUP_CSS = "popup";
public static String CSS_SUFFIX = ".css";
public final static String GLOBAL_CSS = "global";
public final static String POPUP_CSS = "popup";
public final static String CSS_SUFFIX = ".css";
protected void setCss(String css){
String languageCode = "";

@ -0,0 +1,18 @@
package se.su.dsv.scipro.basepages;
import org.apache.wicket.PageParameters;
import se.su.dsv.scipro.security.auth.Authorization;
@Authorization(requiresLoggedInUser = false)
public abstract class PublicPage extends BasePage {
public PublicPage(){
super();
}
public PublicPage(PageParameters pp){
super(pp);
}
}

@ -10,5 +10,14 @@ public interface UserDao extends LazyDeleteDao<User> {
public User getUserByEmail(final String emailAddress);
public boolean isStudent(final User user);
public boolean isExternal(final User user);
public boolean isEmployee(final User user);
public boolean isAdmin(final User user);
public boolean isSysadmin(final User user);
}

@ -67,4 +67,29 @@ public class UserDaoJPAImp extends LazyDeleteAbstractDaoJPAImpl<User> implements
});
}
public boolean isStudent(final User user) {
// TODO Auto-generated method stub
return true;
}
public boolean isExternal(final User user) {
// TODO Auto-generated method stub
return false;
}
public boolean isEmployee(final User user) {
// TODO Auto-generated method stub
return false;
}
public boolean isAdmin(final User user) {
// TODO Auto-generated method stub
return false;
}
public boolean isSysadmin(final User user) {
// TODO Auto-generated method stub
return false;
}
}

@ -9,7 +9,7 @@ import javax.persistence.Table;
*
*/
@Entity
@Table(name="Event")
@Table(name="event")
public class Event extends DomainObject {
private static final long serialVersionUID = 2959377496669050427L;

@ -18,7 +18,7 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
*
*/
@Entity
@Table(name="User")
@Table(name="user")
@Cacheable(true)
@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific
public class User extends LazyDeletableDomainObject {

@ -19,7 +19,7 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
@Entity
@Cacheable(true)
@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific
@Table(name="Username", uniqueConstraints={@UniqueConstraint(columnNames={"username","realm"})})
@Table(name="username", uniqueConstraints={@UniqueConstraint(columnNames={"username","realm"})})
public class Username extends DomainObject {
private static final long serialVersionUID = -2043481766263425696L;

@ -5,7 +5,7 @@ import org.apache.wicket.RestartResponseException;
import se.su.dsv.scipro.HomePage;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.basepages.BasePage;
import se.su.dsv.scipro.basepages.PublicPage;
import se.su.dsv.scipro.loginlogout.panels.LoginPanel;
/**
@ -13,16 +13,10 @@ import se.su.dsv.scipro.loginlogout.panels.LoginPanel;
* @param pp the page parameters
* @author Martin Peters - mpeters@dsv.su.se
*/
public class LoginPage extends BasePage {
public class LoginPage extends PublicPage {
public LoginPage(final PageParameters pp) throws Exception {
//Redirect to HomePage if user is authenticated
if(SciProSession.get().isLoggedIn()){
getRequestCycle().setRedirect(true);
throw new RestartResponseException(HomePage.class);
}
add(new LoginPanel("signInPanel", true));
}

@ -5,14 +5,13 @@ import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.basepages.BasePage;
import se.su.dsv.scipro.basepages.PublicPage;
public class LogoutPage extends BasePage {
public class LogoutPage extends PublicPage {
public LogoutPage(final PageParameters parameters){
SciProSession session = SciProSession.get();
session.invalidate();
SciProSession.get().invalidate();
add(new Label("message", "You are now logged out. Log back in "));
BookmarkablePageLink<Void> bml = new BookmarkablePageLink<Void>("loginLink", LoginPage.class);

@ -16,23 +16,35 @@ import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import se.su.dsv.scipro.basepages.BasePage;
import se.su.dsv.scipro.data.dao.interfaces.EventDao;
import se.su.dsv.scipro.data.dataobjects.Event;
import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.Authorization.ON_AUTH_FAIL;
import se.su.dsv.scipro.security.auth.ComponentSecurity;
import se.su.dsv.scipro.security.auth.MetaDataActionStrategy;
import se.su.dsv.scipro.security.auth.SecurityFailAction;
import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.security.auth.roles.Student;
/**
* @author Richard Wilkinson - richard.wilkinson@jweekend.com
*
*/
public class EventPage extends WebPage {
public class EventPage extends BasePage {
@SpringBean
private EventDao eventDao;
Form<Event> eventForm;
public EventPage(final PageParameters pp)
{
Form<Event> eventForm = new Form<Event>("eventForm", new CompoundPropertyModel<Event>(new Event()));
eventForm = new Form<Event>("eventForm", new CompoundPropertyModel<Event>(new Event()));
eventForm.add(new TextField<String>("title").setRequired(true));
eventForm.add(new TextField<String>("location").setRequired(true));
eventForm.setMetaData(MetaDataActionStrategy.AUTHORIZED_ROLES, new ComponentSecurity(Roles.EMPLOYEE, SecurityFailAction.DISABLE));
final WebMarkupContainer wmc = new WebMarkupContainer("listContainer");
wmc.add(new ListView<Event>("list", new PropertyModel<List<Event>>(this, "eventDao.findAll")){
@ -68,4 +80,5 @@ public class EventPage extends WebPage {
add(eventForm);
}
}

@ -1,4 +1,4 @@
package se.su.dsv.scipro.auth;
package se.su.dsv.scipro.security.auth;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginContext;

@ -0,0 +1,40 @@
package se.su.dsv.scipro.security.auth;
import java.lang.annotation.*;
import se.su.dsv.scipro.security.auth.roles.Roles;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
* @author Niklas Herder for base code
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface Authorization {
enum ON_AUTH_FAIL {
/**
* Disable the component, but show
*/
DISABLE_COMPONENT,
/**
* Hide the component
*/
HIDE_COMPONENT,
}
/**
* Which action to take on this component when authorization fails.
*/
ON_AUTH_FAIL actionOnAuthFail() default ON_AUTH_FAIL.HIDE_COMPONENT;
/**
* Whether the component requires a logged in user
*/
boolean requiresLoggedInUser() default true;
Roles[] authorizedRoles() default {Roles.SYSADMIN};
}

@ -0,0 +1,52 @@
package se.su.dsv.scipro.security.auth;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import se.su.dsv.scipro.security.auth.roles.Roles;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
*
*/
public class ComponentSecurity implements Serializable {
private static final long serialVersionUID = 1L;
private final ArrayList<Roles> authorizedRoles = new ArrayList<Roles>();
private SecurityFailAction failAction;
public ComponentSecurity(Roles role){
this(role, SecurityFailAction.REMOVE);
}
public ComponentSecurity(Roles role, SecurityFailAction action){
authorizedRoles.add(role);
if( action == null )
throw new IllegalArgumentException("FailAction may not be null");
failAction = action;
}
public ComponentSecurity(Roles[] roles){
this(roles, SecurityFailAction.REMOVE);
}
public ComponentSecurity(Roles[] roles, SecurityFailAction action) {
authorizedRoles.addAll(Arrays.asList(roles));
if( action == null )
throw new IllegalArgumentException("FailAction may not be null");
failAction = action;
}
public SecurityFailAction getFailAction(){
return failAction;
}
public List<Roles> getAuthorizedRoles(){
//For security-concerns we don't return the mutable list but a copy
return new ArrayList<Roles>(authorizedRoles);
}
}

@ -0,0 +1,25 @@
package se.su.dsv.scipro.security.auth;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
import se.su.dsv.scipro.SciProApplication;
import se.su.dsv.scipro.SciProSession;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
*
*/
public class ComponentSecurityLogger implements IUnauthorizedComponentInstantiationListener {
public void onUnauthorizedInstantiation(Component component) {
Logger logger = Logger.getLogger("Application");
logger.log(Level.WARN, "User: "+SciProSession.get().getLoggedInIdentity()+ " attempted to instantiate unauthorized page: "+component.getClass());
throw new RestartResponseAtInterceptPageException(SciProApplication.get().getApplicationSettings().getAccessDeniedPage());
}
}

@ -1,4 +1,4 @@
package se.su.dsv.scipro.auth;
package se.su.dsv.scipro.security.auth;
import java.io.IOException;
import javax.security.auth.callback.Callback;

@ -0,0 +1,61 @@
package se.su.dsv.scipro.security.auth;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.security.auth.roles.Roles;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
* Checks for actionAuthorization of components based on component-metadata
*/
public class MetaDataActionStrategy implements IAuthorizationStrategy {
public static final MetaDataKey<ComponentSecurity> AUTHORIZED_ROLES = new MetaDataKey<ComponentSecurity>() {
private static final long serialVersionUID = 1L;
};
public boolean isActionAuthorized(final Component component, final Action action) {
//Get metadata from component, if none return true for any action
ComponentSecurity cs = component.getMetaData(AUTHORIZED_ROLES);
if( cs != null ){
//Check if user is authorized for this role
List<Roles> authorizedRoles = cs.getAuthorizedRoles();
for(Roles role : authorizedRoles){
if(SciProSession.get().authorizedForRole(role))
return true;
}
//If we've left the loop without a return then handle different kinds of failure
if(action.equals(Component.RENDER)){
if( cs.getFailAction().equals(SecurityFailAction.REMOVE))
return false;
else
return true;
}
else if(action.equals(Component.ENABLE)){
//A value of ENABLE = false should be the only logical option left at this point
return false;
/* If more fail actions were implemented consider this code
if(cs.getFailAction().equals(SecurityFailAction.DISABLE))
return false;
else
return true;
*/
} else
throw new IllegalStateException("Should be unreachable code, someone broke something! Unrecognized action: "+action);
}
return true;
}
public <T extends Component> boolean isInstantiationAuthorized(final Class<T> arg0) {
// Doesn't care about instantiation, only cares about action authorization
return true;
}
}

@ -0,0 +1,96 @@
package se.su.dsv.scipro.security.auth;
import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import se.su.dsv.scipro.SciProSession;
import se.su.dsv.scipro.loginlogout.pages.LoginPage;
import se.su.dsv.scipro.security.auth.roles.Roles;
/**
*
* @author Martin Peters - mpeters@dsv.su.se
* @author Niklas Herder for inspiration
*/
public class RoleBasedAuthorizationStrategy implements IAuthorizationStrategy {
public boolean isActionAuthorized(Component component, Action action) {
boolean ok = false;
Class<? extends Component> authRequired = null;
if (component instanceof BookmarkablePageLink<?>) {
//If it's a link: check permissions for the component the link refers to.
BookmarkablePageLink<?> bookmarkablePageLink = (BookmarkablePageLink<?>) component;
authRequired = bookmarkablePageLink.getPageClass();
} else {
//Otherwise check auth for the compoenent
authRequired = component.getClass();
}
//Get the annotation from the class if there is one
Authorization annotation = authRequired.getAnnotation(Authorization.class);
//Not annotated classes aren't checked further
if( annotation == null)
ok = true;
else {
//Check if it's a "public page" or not
if ( !annotation.requiresLoggedInUser() )
ok = true;
else {
//Check for presence of login and if present check for authorization
if( SciProSession.get().isLoggedIn() ){//&& annotation.authorizedRoles().length > 0){ If no roles added, ok will be false
for( Roles role : annotation.authorizedRoles() ){
if( SciProSession.get().authorizedForRole(role) ){
ok = true;
break;
}
}
}
}
//If not ok so far check what to do on fail
if(!ok){
if(action.equals(Component.RENDER)){
if( annotation.actionOnAuthFail() == Authorization.ON_AUTH_FAIL.HIDE_COMPONENT)
ok = false;
else
ok = true;
} else if (action.equals(Component.ENABLE)){
if( annotation.actionOnAuthFail() == Authorization.ON_AUTH_FAIL.DISABLE_COMPONENT)
ok = false;
else
ok = true;
} else
throw new IllegalStateException("Action "+action.getName()+ " is unknown");
}//Auth failed, what to do on fail?
}//There was an annotation present
//TODO: Remove this println
System.out.println("RoleBasedAuthorisationStrategy says authorized: "+ok+" for action "+action.getName()+" on component "+component.getClass());
return ok;
}
public <T extends Component> boolean isInstantiationAuthorized(Class<T> componentClass) {
//Not annotated classes aren't checked further
Authorization annotation = (Authorization) componentClass.getAnnotation(Authorization.class);
if (annotation != null) {
//If component doesn't require login anyone may do it any time
if( !annotation.requiresLoggedInUser() )
return true;
//If page requires login and user isn't logged in, send them to login page first
if( annotation.requiresLoggedInUser() && !SciProSession.get().isLoggedIn())
throw new RestartResponseAtInterceptPageException(LoginPage.class);
//Check the users role for authorization to instantiate the component
for(Roles role : annotation.authorizedRoles()){
if( SciProSession.get().authorizedForRole(role) )
return true;
}
//No roles were added to the annotation or user was not authorized for the roles that were added
return false;
}
return true;
}
}

@ -0,0 +1,17 @@
package se.su.dsv.scipro.security.auth;
/**
* @author Martin Peters - mpeters@dsv.su.se
* @author Niklas Herder for inspiration
* Enumeration of different actions to take when the actionAuthorization fails on a component
*/
public enum SecurityFailAction {
/*
* Disable a component, makes links unclickable, buttons 'grey' etc.
*/
DISABLE,
/*
* Completely removes components instead of rendering them
*/
REMOVE
}

@ -0,0 +1,20 @@
package se.su.dsv.scipro.security.auth.roles;
public class Admin extends DefaultRole {
@Override
public boolean authorizedForRole(Roles role) {
switch(role) {
case SYSADMIN:
return false;
default:
return true;
}
}
@Override
public String toString() {
return "Admin";
}
}

@ -0,0 +1,9 @@
package se.su.dsv.scipro.security.auth.roles;
public class DefaultRole implements Role {
public boolean authorizedForRole(Roles role) {
return false;
}
}

@ -0,0 +1,24 @@
package se.su.dsv.scipro.security.auth.roles;
public class Employee extends DefaultRole {
@Override
public boolean authorizedForRole(Roles role) {
switch(role) {
case EMPLOYEE:
return true;
case EXTERNAL:
return true;
case STUDENT:
return true;
default:
return false;
}
}
@Override
public String toString() {
return "Employee";
}
}

@ -0,0 +1,20 @@
package se.su.dsv.scipro.security.auth.roles;
public class External extends DefaultRole {
@Override
public boolean authorizedForRole(Roles role) {
switch(role) {
case EXTERNAL:
return true;
default:
return false;
}
}
@Override
public String toString() {
return "External";
}
}

@ -0,0 +1,7 @@
package se.su.dsv.scipro.security.auth.roles;
public interface Role {
public boolean authorizedForRole(Roles role);
}

@ -0,0 +1,26 @@
package se.su.dsv.scipro.security.auth.roles;
public enum Roles {
/*
* For students
*/
STUDENT,
/*
* Externals could be given supervisional roles but no administrative rights
*/
EXTERNAL,
/*
* Employees people might have some administrative rights and may have supervisional roles
*/
EMPLOYEE,
/*
* Can do most things
*/
ADMIN,
/*
* Can do everything
*/
SYSADMIN
}

@ -0,0 +1,20 @@
package se.su.dsv.scipro.security.auth.roles;
public class Student extends DefaultRole {
@Override
public boolean authorizedForRole(Roles role) {
switch(role) {
case STUDENT:
return true;
default:
return false;
}
}
@Override
public String toString() {
return "Student";
}
}

@ -0,0 +1,15 @@
package se.su.dsv.scipro.security.auth.roles;
public class SysAdmin extends DefaultRole {
@Override
public boolean authorizedForRole(Roles role) {
return true;
}
@Override
public String toString() {
return "SysAdmin";
}
}