Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correcting a session problem. #6

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,80 @@
package br.com.caelum.vraptor.security.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.authz.aop.AnnotationsAuthorizingMethodInterceptor;
import org.apache.shiro.subject.Subject;

import br.com.caelum.vraptor.security.AuthorizationRestrictionListener;
import br.com.caelum.vraptor.security.annotation.Secured;

@Interceptor
@Secured
public class SecurityInterceptor extends AnnotationsAuthorizingMethodInterceptor {

@Inject private AuthorizationRestrictionListener listener;
@Inject private Subject subject;

public SecurityInterceptor() { super(); }

@AroundInvoke
public Object check(InvocationContext ctx) throws Exception {
try {
assertAuthorized(new InvocationContextToMethodInvocationConverter(ctx));
Class<?> c = ctx.getTarget().getClass();
Method m = ctx.getMethod();

if (!subject.isAuthenticated() && hasAnnotation(c, m, RequiresAuthentication.class)) {
throw new AuthorizationException("Authentication required");
}

if (subject.getPrincipal() != null && hasAnnotation(c, m, RequiresGuest.class)) {
throw new AuthorizationException("Guest required");
}

if (subject.getPrincipal() == null && hasAnnotation(c, m, RequiresUser.class)) {
throw new AuthorizationException("User required");
}

RequiresRoles roles = getAnnotation(c, m, RequiresRoles.class);

if (roles != null) {
subject.checkRoles(Arrays.asList(roles.value()));
}

RequiresPermissions permissions = getAnnotation(c, m, RequiresPermissions.class);

if (permissions != null) {
subject.checkPermissions(permissions.value());
}
return ctx.proceed();
} catch(AuthorizationException e) {
listener.onAuthorizationRestriction(e);
}
return ctx.proceed();
return null;
}

private static class InvocationContextToMethodInvocationConverter implements MethodInvocation {
private final InvocationContext context;

public InvocationContextToMethodInvocationConverter(InvocationContext ctx) {
context = ctx;
}

public Object proceed() throws Throwable {
return context.proceed();
}

public Method getMethod() {
return context.getMethod();
}

public Object[] getArguments() {
return context.getParameters();
}
private static boolean hasAnnotation(Class<?> c, Method m, Class<? extends Annotation> a) {
return m.isAnnotationPresent(a)
|| c.isAnnotationPresent(a)
|| c.getSuperclass().isAnnotationPresent(a);
}

public Object getThis() {
return context.getTarget();
}
private static <A extends Annotation> A getAnnotation(Class<?> c, Method m, Class<A> a) {
return m.isAnnotationPresent(a) ? m.getAnnotation(a)
: c.isAnnotationPresent(a) ? c.getAnnotation(a)
: c.getSuperclass().getAnnotation(a);
}
}
191 changes: 191 additions & 0 deletions src/main/java/br/com/caelum/vraptor/security/produces/SafeSubject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package br.com.caelum.vraptor.security.produces;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.ExecutionException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

public class SafeSubject implements Serializable, Subject {

private Subject subject;

public SafeSubject(Subject subject) {
this.subject = subject;
}

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

@Override
public PrincipalCollection getPrincipals() {
return subject.getPrincipals();
}

@Override
public boolean isPermitted(String permission) {
return subject.isPermitted(permission);
}

@Override
public boolean isPermitted(Permission permission) {
return subject.isPermitted(permission);
}

@Override
public boolean[] isPermitted(String... permissions) {
return subject.isPermitted(permissions);
}

@Override
public boolean[] isPermitted(List<Permission> permissions) {
return subject.isPermitted(permissions);
}

@Override
public boolean isPermittedAll(String... permissions) {
return subject.isPermittedAll(permissions);
}

@Override
public boolean isPermittedAll(Collection<Permission> permissions) {
return subject.isPermittedAll(permissions);
}

@Override
public void checkPermission(String permission)
throws AuthorizationException {
this.subject.checkPermission(permission);
}

@Override
public void checkPermission(Permission permission)
throws AuthorizationException {
this.subject.checkPermission(permission);
}

@Override
public void checkPermissions(String... permissions)
throws AuthorizationException {
this.subject.checkPermissions(permissions);
}

@Override
public void checkPermissions(Collection<Permission> permissions)
throws AuthorizationException {
this.subject.checkPermissions(permissions);
}

@Override
public boolean hasRole(String roleIdentifier) {
return this.subject.hasRole(roleIdentifier);
}

@Override
public boolean[] hasRoles(List<String> roleIdentifiers) {
return this.subject.hasRoles(roleIdentifiers);
}

@Override
public boolean hasAllRoles(Collection<String> roleIdentifiers) {
return this.subject.hasAllRoles(roleIdentifiers);
}

@Override
public void checkRole(String roleIdentifier) throws AuthorizationException {
this.subject.checkRole(roleIdentifier);
}

@Override
public void checkRoles(Collection<String> roleIdentifiers)
throws AuthorizationException {
this.subject.checkRoles(roleIdentifiers);
}

@Override
public void checkRoles(String... roleIdentifiers)
throws AuthorizationException {
this.subject.checkRoles(roleIdentifiers);
}

@Override
public void login(AuthenticationToken token) throws AuthenticationException {
this.subject.login(token);
}

@Override
public boolean isAuthenticated() {
return this.subject.isAuthenticated();
}

@Override
public boolean isRemembered() {
return this.subject.isRemembered();
}

@Override
public Session getSession() {
return this.subject.getSession();
}

@Override
public Session getSession(boolean create) {
return this.subject.getSession(create);
}

@Override
public void logout() {
this.subject.logout();
}

@Override
public <V> V execute(Callable<V> callable) throws ExecutionException {
return this.subject.execute(callable);
}

@Override
public void execute(Runnable runnable) {
this.subject.execute(runnable);
}

@Override
public <V> Callable<V> associateWith(Callable<V> callable) {
return this.subject.associateWith(callable);
}

@Override
public Runnable associateWith(Runnable runnable) {
return this.subject.associateWith(runnable);
}

@Override
public void runAs(PrincipalCollection principals)
throws NullPointerException, IllegalStateException {
this.subject.runAs(principals);
}

@Override
public boolean isRunAs() {
return this.subject.isRunAs();
}

@Override
public PrincipalCollection getPreviousPrincipals() {
return this.subject.getPreviousPrincipals();
}

@Override
public PrincipalCollection releaseRunAs() {
return this.subject.releaseRunAs();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
import java.util.Collection;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.ejb.Startup;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Singleton;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationListener;
Expand All @@ -30,7 +31,8 @@

import br.com.caelum.vraptor.security.strategy.ShiroInitConfigStrategy;

@ApplicationScoped
@Startup
@Singleton
public class SecurityFacade {

@Inject @Any private Instance<AuthenticationListener> authenticationListeners;
Expand Down Expand Up @@ -75,14 +77,14 @@ public SecurityManager getSecurityManager() {
return SecurityUtils.getSecurityManager();
}

@Produces
@Produces @SessionScoped
public Subject getSubject() {
return SecurityUtils.getSubject();
return new SafeSubject( SecurityUtils.getSubject() );
}

@Produces @SessionScoped
public Session getSession() {
return new SafeSession(SecurityUtils.getSubject().getSession());
return new SafeSession( getSubject().getSession() );
}

@Produces
Expand Down
4 changes: 0 additions & 4 deletions src/main/resources/META-INF/beans.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,4 @@
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">

<interceptors>
<class>br.com.caelum.vraptor.security.interceptor.SecurityInterceptor</class>
</interceptors>
</beans>