Merge pull request #662 from Athou/dw8

dropwizard upgrade
This commit is contained in:
Athou
2014-11-01 11:20:44 +01:00
47 changed files with 345 additions and 271 deletions

View File

@@ -0,0 +1,96 @@
package com.commafeed.frontend.auth;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.RequiredArgsConstructor;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.service.UserService;
import com.commafeed.frontend.session.SessionHelper;
import com.google.common.base.Optional;
@RequiredArgsConstructor
public class SecurityCheckFactory extends AbstractContainerRequestValueFactory<User> {
private static final String PREFIX = "Basic";
@Context
HttpServletRequest request;
@Inject
UserService userService;
private final Role role;
private final boolean apiKeyAllowed;
@Override
public User provide() {
Optional<User> user = apiKeyLogin();
if (!user.isPresent()) {
user = basicAuthenticationLogin();
}
if (!user.isPresent()) {
user = cookieSessionLogin(new SessionHelper(request));
}
if (user.isPresent()) {
if (user.get().hasRole(role)) {
return user.get();
} else {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity("You don't have the required role to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
}
} else {
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED)
.entity("Credentials are required to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
}
}
Optional<User> cookieSessionLogin(SessionHelper sessionHelper) {
Optional<User> loggedInUser = sessionHelper.getLoggedInUser();
if (loggedInUser.isPresent()) {
userService.performPostLoginActivities(loggedInUser.get());
}
return loggedInUser;
}
private Optional<User> basicAuthenticationLogin() {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header != null) {
int space = header.indexOf(' ');
if (space > 0) {
String method = header.substring(0, space);
if (PREFIX.equalsIgnoreCase(method)) {
String decoded = B64Code.decode(header.substring(space + 1), StringUtil.__ISO_8859_1);
int i = decoded.indexOf(':');
if (i > 0) {
String username = decoded.substring(0, i);
String password = decoded.substring(i + 1);
return userService.login(username, password);
}
}
}
}
return Optional.absent();
}
private Optional<User> apiKeyLogin() {
String apiKey = request.getParameter("apiKey");
if (apiKey != null && apiKeyAllowed) {
return userService.login(apiKey);
}
return Optional.absent();
}
}

View File

@@ -0,0 +1,64 @@
package com.commafeed.frontend.auth;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.RequiredArgsConstructor;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
import org.glassfish.jersey.server.internal.inject.ParamInjectionResolver;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.server.spi.internal.ValueFactoryProvider;
import com.commafeed.backend.model.User;
import com.commafeed.backend.service.UserService;
@Singleton
public class SecurityCheckFactoryProvider extends AbstractValueFactoryProvider {
@Inject
public SecurityCheckFactoryProvider(final MultivaluedParameterExtractorProvider extractorProvider, final ServiceLocator injector) {
super(extractorProvider, injector, Parameter.Source.UNKNOWN);
}
@Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> classType = parameter.getRawType();
SecurityCheck securityCheck = parameter.getAnnotation(SecurityCheck.class);
if (securityCheck == null)
return null;
if (classType.isAssignableFrom(User.class)) {
return new SecurityCheckFactory(securityCheck.value(), securityCheck.apiKeyAllowed());
} else {
return null;
}
}
public static class SecurityCheckInjectionResolver extends ParamInjectionResolver<SecurityCheck> {
public SecurityCheckInjectionResolver() {
super(SecurityCheckFactoryProvider.class);
}
}
@RequiredArgsConstructor
public static class Binder extends AbstractBinder {
private final UserService userService;
@Override
protected void configure() {
bind(SecurityCheckFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(SecurityCheckInjectionResolver.class).to(new TypeLiteral<InjectionResolver<SecurityCheck>>() {
}).in(Singleton.class);
bind(userService).to(UserService.class);
}
}
}

View File

@@ -1,124 +0,0 @@
package com.commafeed.frontend.auth;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.RequiredArgsConstructor;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.service.UserService;
import com.commafeed.frontend.session.SessionHelper;
import com.google.common.base.Optional;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.api.model.Parameter;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider;
public class SecurityCheckProvider implements InjectableProvider<SecurityCheck, Parameter> {
public static class SecurityCheckUserServiceProvider extends SingletonTypeInjectableProvider<Context, UserService> {
public SecurityCheckUserServiceProvider(UserService userService) {
super(UserService.class, userService);
}
}
@RequiredArgsConstructor
static class SecurityCheckInjectable extends AbstractHttpContextInjectable<User> {
private static final String PREFIX = "Basic";
private final SessionHelper sessionHelper;
private final UserService userService;
private final Role role;
private final boolean apiKeyAllowed;
@Override
public User getValue(HttpContext c) {
Optional<User> user = apiKeyLogin(c);
if (!user.isPresent()) {
user = basicAuthenticationLogin(c);
}
if (!user.isPresent()) {
user = cookieSessionLogin();
}
if (user.isPresent()) {
if (user.get().hasRole(role)) {
return user.get();
} else {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity("You don't have the required role to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
}
} else {
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED)
.entity("Credentials are required to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
}
}
Optional<User> cookieSessionLogin() {
Optional<User> loggedInUser = sessionHelper.getLoggedInUser();
if (loggedInUser.isPresent()) {
userService.performPostLoginActivities(loggedInUser.get());
}
return loggedInUser;
}
private Optional<User> basicAuthenticationLogin(HttpContext c) {
String header = c.getRequest().getHeaderValue(HttpHeaders.AUTHORIZATION);
if (header != null) {
int space = header.indexOf(' ');
if (space > 0) {
String method = header.substring(0, space);
if (PREFIX.equalsIgnoreCase(method)) {
String decoded = B64Code.decode(header.substring(space + 1), StringUtil.__ISO_8859_1);
int i = decoded.indexOf(':');
if (i > 0) {
String username = decoded.substring(0, i);
String password = decoded.substring(i + 1);
return userService.login(username, password);
}
}
}
}
return Optional.absent();
}
private Optional<User> apiKeyLogin(HttpContext c) {
String apiKey = c.getUriInfo().getQueryParameters().getFirst("apiKey");
if (apiKey != null && apiKeyAllowed) {
return userService.login(apiKey);
}
return Optional.absent();
}
}
private SessionHelper sessionHelper;
private UserService userService;
public SecurityCheckProvider(@Context HttpServletRequest req, @Context UserService userService) {
this.sessionHelper = new SessionHelper(req);
this.userService = userService;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
@Override
public Injectable<?> getInjectable(ComponentContext ic, SecurityCheck sc, Parameter c) {
return new SecurityCheckInjectable(sessionHelper, userService, sc.value(), sc.apiKeyAllowed());
}
}

View File

@@ -19,7 +19,7 @@ import javax.ws.rs.core.Response.Status;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import com.codahale.metrics.MetricRegistry;
import com.commafeed.CommaFeedApplication;

View File

@@ -9,6 +9,7 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -27,8 +28,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.cache.CacheService;
@@ -360,7 +361,7 @@ public class CategoryREST {
int existingIndex = -1;
for (int i = 0; i < categories.size(); i++) {
if (ObjectUtils.equals(categories.get(i).getId(), category.getId())) {
if (Objects.equals(categories.get(i).getId(), category.getId())) {
existingIndex = i;
}
}
@@ -437,7 +438,7 @@ public class CategoryREST {
category.setExpanded(true);
for (FeedCategory c : categories) {
if ((id == null && c.getParent() == null) || (c.getParent() != null && ObjectUtils.equals(c.getParent().getId(), id))) {
if ((id == null && c.getParent() == null) || (c.getParent() != null && Objects.equals(c.getParent().getId(), id))) {
Category child = buildCategory(c.getId(), categories, subscriptions, unreadCount);
child.setId(String.valueOf(c.getId()));
child.setName(c.getName());
@@ -458,7 +459,7 @@ public class CategoryREST {
for (FeedSubscription subscription : subscriptions) {
if ((id == null && subscription.getCategory() == null)
|| (subscription.getCategory() != null && ObjectUtils.equals(subscription.getCategory().getId(), id))) {
|| (subscription.getCategory() != null && Objects.equals(subscription.getCategory().getId(), id))) {
UnreadCount uc = unreadCount.get(subscription.getId());
Subscription sub = Subscription.build(subscription, config.getApplicationSettings().getPublicUrl(), uc);
category.getFeeds().add(sub);

View File

@@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -33,8 +34,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.media.multipart.FormDataParam;
import com.commafeed.CommaFeedApplication;
import com.commafeed.CommaFeedConfiguration;
@@ -78,7 +80,6 @@ import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.feed.synd.SyndFeedImpl;
import com.rometools.rome.io.SyndFeedOutput;
import com.rometools.rome.io.WireFeedOutput;
import com.sun.jersey.multipart.FormDataParam;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
@@ -440,7 +441,7 @@ public class FeedREST {
int existingIndex = -1;
for (int i = 0; i < subs.size(); i++) {
if (ObjectUtils.equals(subs.get(i).getId(), subscription.getId())) {
if (Objects.equals(subs.get(i).getId(), subscription.getId())) {
existingIndex = i;
}
}

View File

@@ -23,8 +23,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.codahale.metrics.MetricRegistry;
import com.commafeed.CommaFeedConfiguration;

View File

@@ -15,7 +15,7 @@ import javax.ws.rs.core.Response.Status;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.HttpGetter;

View File

@@ -27,9 +27,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.client.utils.URIBuilder;
import com.commafeed.CommaFeedApplication;

View File

@@ -9,7 +9,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import com.commafeed.CommaFeedConfiguration;

View File

@@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SessionFactory;
import com.commafeed.CommaFeedConfiguration;

View File

@@ -0,0 +1,17 @@
package com.commafeed.frontend.session;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
public class SessionHelperFactory extends AbstractContainerRequestValueFactory<SessionHelper> {
@Context
HttpServletRequest request;
@Override
public SessionHelper provide() {
return new SessionHelper(request);
}
}

View File

@@ -0,0 +1,56 @@
package com.commafeed.frontend.session;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.core.Context;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
import org.glassfish.jersey.server.internal.inject.ParamInjectionResolver;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.server.spi.internal.ValueFactoryProvider;
@Singleton
public class SessionHelperFactoryProvider extends AbstractValueFactoryProvider {
@Inject
public SessionHelperFactoryProvider(final MultivaluedParameterExtractorProvider extractorProvider, final ServiceLocator injector) {
super(extractorProvider, injector, Parameter.Source.CONTEXT);
}
@Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> classType = parameter.getRawType();
Context context = parameter.getAnnotation(Context.class);
if (context == null)
return null;
if (classType.isAssignableFrom(SessionHelper.class)) {
return new SessionHelperFactory();
} else {
return null;
}
}
public static class SessionHelperInjectionResolver extends ParamInjectionResolver<Context> {
public SessionHelperInjectionResolver() {
super(SessionHelperFactoryProvider.class);
}
}
public static class Binder extends AbstractBinder {
@Override
protected void configure() {
bind(SessionHelperFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
bind(SessionHelperInjectionResolver.class).to(new TypeLiteral<InjectionResolver<Context>>() {
}).in(Singleton.class);
}
}
}

View File

@@ -1,44 +0,0 @@
package com.commafeed.frontend.session;
import java.lang.reflect.Type;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
@Provider
public class SessionHelperProvider implements InjectableProvider<Context, Type> {
private final ThreadLocal<HttpServletRequest> request;
public SessionHelperProvider(@Context ThreadLocal<HttpServletRequest> request) {
this.request = request;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
@Override
public Injectable<?> getInjectable(ComponentContext ic, final Context session, Type type) {
if (type.equals(SessionHelper.class)) {
return new Injectable<SessionHelper>() {
@Override
public SessionHelper getValue() {
final HttpServletRequest req = request.get();
if (req != null) {
return new SessionHelper(req);
}
return null;
}
};
}
return null;
}
}