<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-logger</artifactId>
<version>1.0.0-CR2</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>6.0</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.1.EDR1.2</version>
</dependency>
</dependencies>
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# INI configuration is very powerful and flexible, while still remaining succinct.
# Please http://shiro.apache.org/configuration.html and
# http://shiro.apache.org/web.html for more.
[main]
# listener = org.apache.shiro.config.event.LoggingBeanListener
shiro.loginUrl = /login.xhtml
[users]
# format: username = password, role1, role2, ..., roleN
root = secret,admin
guest = guest,guest
presidentskroob = 12345,president
darkhelmet = ludicrousspeed,darklord,schwartz
lonestarr = vespa,goodguy,schwartz
[roles]
# format: roleName = permission1, permission2, ..., permissionN
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
[urls]
# The /login.jsp is not restricted to authenticated users (otherwise no one could log in!), but
# the 'authc' filter must still be specified for it so it can process that url's
# login submissions. It is 'smart' enough to allow those requests through as specified by the
# shiro.loginUrl above.
/login.xhtml = authc
/logout = logout
/account/** = authc
/remoting/** = authc, roles[b2bClient], perms["remote:invoke:lan,wan"]
package com.czetsuya.commons.web.security.shiro;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Edward P. Legaspi
* @since Oct 10, 2012
*/
@Secured
@Interceptor
public class SecurityInterceptor {
@Inject
private Subject subject;
private Logger log = LoggerFactory.getLogger(SecurityInterceptor.class);
@AroundInvoke
public Object interceptGet(InvocationContext ctx) throws Exception {
log.info("Securing {}.{}({})", new Object[] { ctx.getClass().getName(),
ctx.getMethod(), ctx.getParameters() });
final Class<? extends Object> runtimeClass = ctx.getTarget().getClass();
// Check if user is authenticated
boolean requiresAuthentication = false;
try { // check method first
ctx.getMethod().getAnnotation(RequiresAuthentication.class);
requiresAuthentication = true;
} catch (NullPointerException e) {
requiresAuthentication = false;
}
if (!requiresAuthentication) { // check class level
try {
runtimeClass.getAnnotation(RequiresAuthentication.class);
requiresAuthentication = true;
} catch (NullPointerException e) {
requiresAuthentication = false;
}
}
if (requiresAuthentication) {
log.debug("[security] checking for authenticated user.");
try {
if (!subject.isAuthenticated()) {
throw new AuthorizationException();
}
} catch (Exception e) {
log.error("Access denied - {}: {}", e.getClass().getName(),
e.getMessage());
throw e;
}
}
/************************************************************/
// check if user has roles
boolean requiresRoles = false;
List<String> listOfRoles = null;
try { // check method first
RequiresRoles roles = ctx.getMethod().getAnnotation(
RequiresRoles.class);
listOfRoles = Arrays.asList(roles.value());
requiresRoles = true;
} catch (NullPointerException e) {
requiresRoles = false;
}
if (!requiresRoles || listOfRoles == null) { // check class
try {
RequiresRoles roles = runtimeClass
.getAnnotation(RequiresRoles.class);
listOfRoles = Arrays.asList(roles.value());
requiresRoles = true;
} catch (NullPointerException e) {
requiresRoles = false;
}
}
if (requiresRoles && listOfRoles != null) {
log.debug("[security] checking for roles.");
try {
boolean[] boolRoles = subject.hasRoles(listOfRoles);
boolean roleVerified = false;
for (boolean b : boolRoles) {
if (b) {
roleVerified = true;
break;
}
}
if (!roleVerified) {
throw new AuthorizationException(
"Access denied. User doesn't have enough privilege Roles:"
+ listOfRoles + " to access this page.");
}
} catch (Exception e) {
log.error("Access denied - {}: {}", e.getClass().getName(),
e.getMessage());
throw e;
}
}
/************************************************************/
// and lastly check for permissions
boolean requiresPermissions = false;
List<String> listOfPermissionsString = null;
try { // check method first
RequiresPermissions permissions = ctx.getMethod().getAnnotation(
RequiresPermissions.class);
listOfPermissionsString = Arrays.asList(permissions.value());
requiresPermissions = true;
} catch (NullPointerException e) {
requiresPermissions = false;
}
if (!requiresPermissions || listOfPermissionsString == null) {
// check class
try {
RequiresPermissions permissions = runtimeClass
.getAnnotation(RequiresPermissions.class);
listOfPermissionsString = Arrays.asList(permissions.value());
requiresPermissions = true;
} catch (NullPointerException e) {
requiresPermissions = false;
}
}
if (requiresPermissions && listOfPermissionsString != null) {
log.debug("[security] checking for permissions.");
List<Permission> listOfPermissions = new ArrayList<Permission>();
for (String p : listOfPermissionsString) {
listOfPermissions.add((Permission) new WildcardPermission(p));
}
try {
boolean[] boolPermissions = subject
.isPermitted(listOfPermissions);
boolean permitted = false;
for (boolean b : boolPermissions) {
if (b) {
permitted = true;
break;
}
}
if (!permitted) {
throw new AuthorizationException(
"Access denied. User doesn't have enough privilege Permissions:"
+ listOfRoles + " to access this page.");
}
} catch (Exception e) {
log.error("Access denied - {}: {}", e.getClass().getName(),
e.getMessage());
throw e;
}
}
return ctx.proceed();
}
}
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>com.czetsuya.commons.web.security.shiro.SecurityInterceptor</class>
</interceptors>
</beans>
package com.czetsuya.commons.web.security.shiro;
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;
import javax.interceptor.InterceptorBinding;
/**
* @author Edward P. Legaspi
* @since Oct 10, 2012
*/
@Inherited
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
public @interface Secured {
}
package com.czetsuya.commons.web.security.shiro;
import javax.annotation.PostConstruct;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Edward P. Legaspi
* @since Oct 10, 2012 Produces an instance of Shiro's subject so that it can be
* injected.
*/
@Singleton
public class SecurityProducer {
Logger logger = LoggerFactory.getLogger(SecurityProducer.class);
private SecurityManager securityManager;
@PostConstruct
public void init() {
final String iniFile = "classpath:shiro.ini";
logger.info("Initializing Shiro INI SecurityManager using " + iniFile);
securityManager = new IniSecurityManagerFactory(iniFile).getInstance();
SecurityUtils.setSecurityManager(securityManager);
}
@Produces
@Named("securityManager")
public SecurityManager getSecurityManager() {
return securityManager;
}
@Produces
public Subject getSubject() {
return SecurityUtils.getSubject();
}
}
package com.czetsuya.mbeans;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import com.czetsuya.commons.web.security.shiro.Secured;
/**
* @author Edward P. Legaspi
* @since Oct 10, 2012
*/
@LocalBean
@Named
@Stateless
public class LoginBean {
@Inject
private Subject subject;
@Inject
private Logger log;
private String username;
private String password;
public String login() {
if (subject.isAuthenticated()) {
log.debug("[czetsuya-ejbs] active subject={}, user={}", subject,
subject.getPrincipal());
return redirect();
} else {
log.debug(
"[czetsuya-ejbs] login to the system with user={}, password={}",
getUsername(), getPassword());
AuthenticationToken token = new UsernamePasswordToken(
getUsername(), getPassword());
try {
subject.login(token);
return redirect();
} catch (Exception e) {
log.error("[czetsuya-ejbs] error login {}", e);
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Error login"));
}
}
return "home.xhtml";
}
public String logout() {
log.debug("[czetsuya-ejbs] logout");
if (subject.isAuthenticated()) {
subject.logout();
}
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Logout Ok"));
return "login.xhtml";
}
private String redirect() {
log.debug("[czetsuya-ejbs] redirect");
if (subject.hasRole("admin")) {
return "admin.xhtml";
} else if (subject.hasRole("schwartz")) {
return "schwartz.xhtml";
} else if (subject.hasRole("goodguy")) {
return "goodguy.xhtml";
}
return "home.xhtml";
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Secured
@RequiresAuthentication
public String requiresAuthentication() {
return "";
}
@Secured
@RequiresRoles({ "admin" })
public void requiresRolesMerchant() {
log.debug("admin");
}
@Secured
@RequiresRoles({ "schwartz" })
public void requiresRolesSupport() {
log.debug("schwartz");
}
@Secured
@RequiresPermissions({ "lightsaber" })
public void requiresPermissionlightsaber() {
log.debug("lightsaber.action");
}
@Secured
@RequiresPermissions({ "winnebago" })
public void requiresPermissionSupport() {
log.debug("winnebago.action");
}
@Secured
@RequiresPermissions({ "winnebago", "lightsaber" })
public void requiresPermissionlightsaberOrwinnebago() {
log.debug("winnebago+lightsaber.action");
}
}
Related:
Seam Security: http://czetsuya-tech.blogspot.com/2013/06/how-to-setup-seam3-security-in-jboss-7.html