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

Fixes #254 - do not call ctx.proceed() if it was already called in RememberMe interceptor #373

Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,55 +58,56 @@
public class RememberMeInterceptor implements Serializable {

private static final long serialVersionUID = 1L;

@Inject
private BeanManager beanManager;

@Inject
@Intercepted
private Bean<?> interceptedBean;

@AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Exception {

// If intercepting HttpAuthenticationMechanism#validateRequest
if (isImplementationOf(invocationContext.getMethod(), validateRequestMethod)) {
return validateRequest(
invocationContext,
getParam(invocationContext, 0),
invocationContext,
getParam(invocationContext, 0),
getParam(invocationContext, 1),
getParam(invocationContext, 2));
}

// If intercepting HttpAuthenticationMechanism#cleanSubject
if (isImplementationOf(invocationContext.getMethod(), cleanSubjectMethod)) {
cleanSubject(
invocationContext,
getParam(invocationContext, 0),
invocationContext,
getParam(invocationContext, 0),
getParam(invocationContext, 1),
getParam(invocationContext, 2));
getParam(invocationContext, 2));
return null;
}

return invocationContext.proceed();
}

private AuthenticationStatus validateRequest(InvocationContext invocationContext, HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws Exception {

RememberMeIdentityStore rememberMeIdentityStore = CdiUtils.getBeanReference(RememberMeIdentityStore.class);
RememberMe rememberMeAnnotation = getRememberMeFromIntercepted(getElProcessor(invocationContext, httpMessageContext), invocationContext);

Cookie rememberMeCookie = getCookie(request, rememberMeAnnotation.cookieName());

if (rememberMeCookie != null) {

// There's a remember me cookie, see if we can use it to authenticate

CredentialValidationResult result = rememberMeIdentityStore.validate(
new RememberMeCredential(rememberMeCookie.getValue())
);

if (result.getStatus() == VALID) {
// The remember me store contained an authenticated identity associated with
// The remember me store contained an authenticated identity associated with
// the given token, use it to authenticate with the container
return httpMessageContext.notifyContainerAboutLogin(
result.getCallerPrincipal(), result.getCallerGroups());
Expand All @@ -116,91 +117,91 @@ private AuthenticationStatus validateRequest(InvocationContext invocationContext
removeCookie(request, response, rememberMeAnnotation.cookieName());
}
}

// Try to authenticate with the next interceptor or actual authentication mechanism
AuthenticationStatus authstatus = (AuthenticationStatus) invocationContext.proceed();

if (authstatus == AuthenticationStatus.SUCCESS && httpMessageContext.getCallerPrincipal() != null) {

// Authentication succeeded;
// Check if remember me is wanted by the caller and if so
// store the authenticated identity in the remember me store
// and send a cookie with a token that can be used
// to retrieve this stored identity later

Boolean isRememberMe = true;
if (rememberMeAnnotation instanceof RememberMeAnnotationLiteral) { // tmp
isRememberMe = ((RememberMeAnnotationLiteral)rememberMeAnnotation).isRememberMe();
}

if (isRememberMe) {
String token = rememberMeIdentityStore.generateLoginToken(
toCallerPrincipal(httpMessageContext.getCallerPrincipal()),
httpMessageContext.getGroups()
);

saveCookie(
request, response,
rememberMeAnnotation.cookieName(),
token,
request, response,
rememberMeAnnotation.cookieName(),
token,
rememberMeAnnotation.cookieMaxAgeSeconds(),
rememberMeAnnotation.cookieSecureOnly(),
rememberMeAnnotation.cookieHttpOnly());
}
}

return authstatus;
}

private void cleanSubject(InvocationContext invocationContext, HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws Exception {

RememberMeIdentityStore rememberMeIdentityStore = CdiUtils.getBeanReference(RememberMeIdentityStore.class); // TODO ADD CHECKS
RememberMe rememberMeAnnotation = getRememberMeFromIntercepted(getElProcessor(invocationContext, httpMessageContext), invocationContext);

Cookie rememberMeCookie = getCookie(request, rememberMeAnnotation.cookieName());

if (rememberMeCookie != null) {

// There's a remember me cookie, remove the cookie
removeCookie(request, response, rememberMeAnnotation.cookieName());

// And remove the token (and with it the authenticated identity) from the store
rememberMeIdentityStore.removeLoginToken(rememberMeCookie.getValue());
}

invocationContext.proceed();
}

private RememberMe getRememberMeFromIntercepted(ELProcessor elProcessor, InvocationContext invocationContext) {
Optional<RememberMe> optionalRememberMe = getAnnotation(beanManager, interceptedBean.getBeanClass(), RememberMe.class);
if (optionalRememberMe.isPresent()) {
return RememberMeAnnotationLiteral.eval(optionalRememberMe.get(), elProcessor);
}

@SuppressWarnings("unchecked")
Set<Annotation> bindings = (Set<Annotation>) invocationContext.getContextData().get("org.jboss.weld.interceptor.bindings");
if (bindings != null) {
optionalRememberMe = bindings.stream()
.filter(annotation -> annotation.annotationType().equals(RememberMe.class))
.findAny()
.map(annotation -> RememberMe.class.cast(annotation));

if (optionalRememberMe.isPresent()) {
return RememberMeAnnotationLiteral.eval(optionalRememberMe.get(), elProcessor);
}
}

throw new IllegalStateException("@RememberMe not present on " + interceptedBean.getBeanClass());
}

private ELProcessor getElProcessor(InvocationContext invocationContext, HttpMessageContext httpMessageContext) {
ELProcessor elProcessor = new ELProcessor();

elProcessor.getELManager().addELResolver(beanManager.getELResolver());
elProcessor.defineBean("self", invocationContext.getTarget());
elProcessor.defineBean("httpMessageContext", httpMessageContext);

return elProcessor;
}

}