security revamp

This commit is contained in:
Athou
2014-08-08 21:57:16 +02:00
parent 9d070bd33c
commit c56c213da7
17 changed files with 209 additions and 91 deletions

View File

@@ -1,5 +1,5 @@
app:
publicUrl: http://localhost:8083/
publicUrl: http://localhost:8082/
allowRegistrations: false
googleAnalyticsTrackingCode:
googleClientId:
@@ -38,8 +38,10 @@ database:
server:
applicationConnectors:
- type: http
port: 8082
port: 8083
adminConnectors:
- type: http
port: 8084
logging:
level: WARN
loggers:

View File

@@ -63,9 +63,9 @@ gulp.task('watch', function() {
gulp.task('serve', function() {
connect.server({
root : BUILD_DIR,
port : 8083,
port : 8082,
middleware : function() {
return [modRewrite(['^/rest/(.*)$ http://localhost:8082/rest/$1 [P]'])];
return [modRewrite(['^/rest/(.*)$ http://localhost:8083/rest/$1 [P]'])];
}
});
});

View File

@@ -137,11 +137,6 @@
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-auth</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-hibernate</artifactId>

View File

@@ -2,9 +2,6 @@ package com.commafeed;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.auth.CachingAuthenticator;
import io.dropwizard.auth.basic.BasicAuthProvider;
import io.dropwizard.auth.basic.BasicCredentials;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.migrations.MigrationsBundle;
@@ -61,6 +58,7 @@ import com.commafeed.backend.service.PasswordEncryptionService;
import com.commafeed.backend.service.PubSubService;
import com.commafeed.backend.service.StartupService;
import com.commafeed.backend.service.UserService;
import com.commafeed.frontend.auth.SecurityCheckProvider;
import com.commafeed.frontend.resource.AdminREST;
import com.commafeed.frontend.resource.CategoryREST;
import com.commafeed.frontend.resource.EntryREST;
@@ -152,9 +150,8 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
FeedRefreshWorker feedWorker = new FeedRefreshWorker(feedUpdater, feedFetcher, queues, config, metrics);
FeedRefreshTaskGiver taskGiver = new FeedRefreshTaskGiver(sessionFactory, queues, feedDAO, feedWorker, config, metrics);
CachingAuthenticator<BasicCredentials, User> cachingAuthenticator = new CachingAuthenticator<BasicCredentials, User>(
environment.metrics(), new CommaFeedAuthenticator(userService), config.getAuthenticationCachePolicy());
environment.jersey().register(new BasicAuthProvider<User>(cachingAuthenticator, "CommaFeed"));
// TODO add caching of credentials somehow
environment.jersey().register(new SecurityCheckProvider(userService));
environment.jersey().setUrlPattern("/rest/*");
environment.jersey()

View File

@@ -1,21 +0,0 @@
package com.commafeed;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
import lombok.RequiredArgsConstructor;
import com.commafeed.backend.model.User;
import com.commafeed.backend.service.UserService;
import com.google.common.base.Optional;
@RequiredArgsConstructor
public class CommaFeedAuthenticator implements Authenticator<BasicCredentials, User> {
private final UserService userService;
@Override
public Optional<User> authenticate(final BasicCredentials credentials) throws AuthenticationException {
return Optional.fromNullable(userService.login(credentials.getUsername(), credentials.getPassword()));
}
}

View File

@@ -3,6 +3,7 @@ package com.commafeed.backend.dao;
import org.hibernate.SessionFactory;
import com.commafeed.backend.model.QUser;
import com.commafeed.backend.model.QUserRole;
import com.commafeed.backend.model.User;
public class UserDAO extends GenericDAO<User> {
@@ -14,14 +15,17 @@ public class UserDAO extends GenericDAO<User> {
}
public User findByName(String name) {
return newQuery().from(user).where(user.name.equalsIgnoreCase(name)).uniqueResult(user);
return newQuery().from(user).where(user.name.equalsIgnoreCase(name)).leftJoin(user.roles, QUserRole.userRole).fetch()
.uniqueResult(user);
}
public User findByApiKey(String key) {
return newQuery().from(user).where(user.apiKey.equalsIgnoreCase(key)).uniqueResult(user);
return newQuery().from(user).where(user.apiKey.equalsIgnoreCase(key)).leftJoin(user.roles, QUserRole.userRole).fetch()
.uniqueResult(user);
}
public User findByEmail(String email) {
return newQuery().from(user).where(user.email.equalsIgnoreCase(email)).uniqueResult(user);
return newQuery().from(user).where(user.email.equalsIgnoreCase(email)).leftJoin(user.roles, QUserRole.userRole).fetch()
.uniqueResult(user);
}
}

View File

@@ -17,6 +17,7 @@ import lombok.Setter;
import org.hibernate.annotations.Cascade;
import com.commafeed.backend.model.UserRole.Role;
import com.google.common.collect.Sets;
@Entity
@@ -68,4 +69,13 @@ public class User extends AbstractModel {
@Temporal(TemporalType.TIMESTAMP)
private Date lastFullRefresh;
public boolean hasRole(Role role) {
for (UserRole userRole : getRoles()) {
if (userRole.getRole() == role) {
return true;
}
}
return false;
}
}

View File

@@ -20,7 +20,7 @@ import lombok.Setter;
public class UserRole extends AbstractModel {
public static enum Role {
USER, ADMIN, NONE
USER, ADMIN
}
@OneToOne(fetch = FetchType.LAZY)

View File

@@ -64,6 +64,18 @@ public class UserService {
return null;
}
public User login(String apiKey) {
if (apiKey == null) {
return null;
}
User user = userDAO.findByApiKey(apiKey);
if (user != null && !user.isDisabled()) {
return user;
}
return null;
}
public User register(String name, String password, String email, Collection<Role> roles) {
return register(name, password, email, roles, false);
}

View File

@@ -0,0 +1,22 @@
package com.commafeed.frontend.auth;
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 com.commafeed.backend.model.UserRole.Role;
@Inherited
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityCheck {
/**
* Roles needed.
*/
Role value() default Role.USER;
boolean apiKeyAllowed() default false;
}

View File

@@ -0,0 +1,95 @@
package com.commafeed.frontend.auth;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import lombok.extern.slf4j.Slf4j;
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.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;
@Slf4j
public class SecurityCheckProvider implements InjectableProvider<SecurityCheck, Parameter> {
private static class SecurityCheckInjectable<T> extends AbstractHttpContextInjectable<User> {
private static final String PREFIX = "Basic";
private final UserService userService;
private Role role;
private final boolean apiKeyAllowed;
private SecurityCheckInjectable(UserService userService, Role role, boolean apiKeyAllowed) {
this.userService = userService;
this.role = role;
this.apiKeyAllowed = apiKeyAllowed;
}
@Override
public User getValue(HttpContext c) {
final String header = c.getRequest().getHeaderValue(HttpHeaders.AUTHORIZATION);
try {
if (header != null) {
final int space = header.indexOf(' ');
if (space > 0) {
final String method = header.substring(0, space);
if (PREFIX.equalsIgnoreCase(method)) {
final String decoded = B64Code.decode(header.substring(space + 1), StringUtil.__ISO_8859_1);
final int i = decoded.indexOf(':');
if (i > 0) {
final String username = decoded.substring(0, i);
final String password = decoded.substring(i + 1);
final User user = userService.login(username, password);
if (user != null && user.hasRole(role)) {
return user;
}
}
}
}
} else {
String apiKey = c.getUriInfo().getPathParameters().getFirst("apiKey");
if (apiKey != null && apiKeyAllowed) {
User user = userService.login(apiKey);
if (user != null && user.hasRole(role)) {
return user;
}
}
}
} catch (IllegalArgumentException e) {
log.debug("Error decoding credentials", e);
}
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"CommaFeed\"")
.entity("Credentials are required to access this resource.").type(MediaType.TEXT_PLAIN_TYPE).build());
}
}
private UserService userService;
public SecurityCheckProvider(UserService userService) {
this.userService = userService;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
@Override
public Injectable<?> getInjectable(ComponentContext ic, SecurityCheck sc, Parameter c) {
return new SecurityCheckInjectable<>(userService, sc.value(), sc.apiKeyAllowed());
}
}

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.Map;
@@ -32,6 +31,7 @@ import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.service.DatabaseCleaningService;
import com.commafeed.backend.service.PasswordEncryptionService;
import com.commafeed.backend.service.UserService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.UserModel;
import com.commafeed.frontend.model.request.IDRequest;
import com.google.common.base.Preconditions;
@@ -62,7 +62,7 @@ public class AdminREST {
@POST
@UnitOfWork
@ApiOperation(value = "Save or update a user", notes = "Save or update a user. If the id is not specified, a new user will be created")
public Response save(@Auth User user, @ApiParam(required = true) UserModel userModel) {
public Response save(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) UserModel userModel) {
Preconditions.checkNotNull(userModel);
Preconditions.checkNotNull(userModel.getName());
@@ -115,7 +115,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Get user information", notes = "Get user information", response = UserModel.class)
public Response getUser(@Auth User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
public Response getUser(@SecurityCheck(Role.ADMIN) User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
User u = userDAO.findById(id);
UserModel userModel = new UserModel();
@@ -135,7 +135,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Get all users", notes = "Get all users", response = UserModel.class, responseContainer = "List")
public Response getUsers(@Auth User user) {
public Response getUsers(@SecurityCheck(Role.ADMIN) User user) {
Map<Long, UserModel> users = Maps.newHashMap();
for (UserRole role : userRoleDAO.findAll()) {
User u = role.getUser();
@@ -162,7 +162,7 @@ public class AdminREST {
@POST
@UnitOfWork
@ApiOperation(value = "Delete a user", notes = "Delete a user, and all his subscriptions")
public Response delete(@Auth User user, @ApiParam(required = true) IDRequest req) {
public Response delete(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -181,7 +181,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Retrieve application settings", notes = "Retrieve application settings", response = ApplicationSettings.class)
public Response getSettings(@Auth User user) {
public Response getSettings(@SecurityCheck(Role.ADMIN) User user) {
return Response.ok(config.getApplicationSettings()).build();
}
@@ -189,7 +189,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Retrieve server metrics")
public Response getMetrics(@Auth User user) {
public Response getMetrics(@SecurityCheck(Role.ADMIN) User user) {
return Response.ok(metrics).build();
}
@@ -197,7 +197,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Entries cleanup", notes = "Delete entries without subscriptions")
public Response cleanupEntries(@Auth User user) {
public Response cleanupEntries(@SecurityCheck(Role.ADMIN) User user) {
Map<String, Long> map = Maps.newHashMap();
map.put("entries_without_subscriptions", cleaner.cleanEntriesWithoutSubscriptions());
return Response.ok(map).build();
@@ -207,7 +207,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Feeds cleanup", notes = "Delete feeds without subscriptions")
public Response cleanupFeeds(@Auth User user) {
public Response cleanupFeeds(@SecurityCheck(Role.ADMIN) User user) {
Map<String, Long> map = Maps.newHashMap();
map.put("feeds_without_subscriptions", cleaner.cleanFeedsWithoutSubscriptions());
return Response.ok(map).build();
@@ -217,7 +217,7 @@ public class AdminREST {
@GET
@UnitOfWork
@ApiOperation(value = "Content cleanup", notes = "Delete contents without entries")
public Response cleanupContents(@Auth User user) {
public Response cleanupContents(@SecurityCheck(Role.ADMIN) User user) {
Map<String, Long> map = Maps.newHashMap();
map.put("contents_without_entries", cleaner.cleanContentsWithoutEntries());
return Response.ok(map).build();

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.io.StringWriter;
@@ -43,6 +42,7 @@ import com.commafeed.backend.model.UserSettings.ReadingMode;
import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.backend.service.FeedEntryService;
import com.commafeed.backend.service.FeedSubscriptionService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.Category;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
@@ -88,7 +88,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Get category entries", notes = "Get a list of category entries", response = Entries.class)
public Response getCategoryEntries(
@Auth User user,
@SecurityCheck User user,
@ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@@ -186,7 +186,7 @@ public class CategoryREST {
@ApiOperation(value = "Get category entries as feed", notes = "Get a feed of category entries")
@Produces(MediaType.APPLICATION_XML)
public Response getCategoryEntriesAsFeed(
@Auth User user,
@SecurityCheck(apiKeyAllowed = true) User user,
@ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@@ -234,7 +234,8 @@ public class CategoryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark category entries", notes = "Mark feed entries of this category as read")
public Response markCategoryEntries(@Auth User user, @ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) {
public Response markCategoryEntries(@SecurityCheck User user,
@ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -272,7 +273,7 @@ public class CategoryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Add a category", notes = "Add a new feed category", response = Long.class)
public Response addCategory(@Auth User user, @ApiParam(required = true) AddCategoryRequest req) {
public Response addCategory(@SecurityCheck User user, @ApiParam(required = true) AddCategoryRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getName());
@@ -295,7 +296,7 @@ public class CategoryREST {
@Path("/delete")
@UnitOfWork
@ApiOperation(value = "Delete a category", notes = "Delete an existing feed category")
public Response deleteCategory(@Auth User user, @ApiParam(required = true) IDRequest req) {
public Response deleteCategory(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -327,7 +328,7 @@ public class CategoryREST {
@Path("/modify")
@UnitOfWork
@ApiOperation(value = "Rename a category", notes = "Rename an existing feed category")
public Response modifyCategory(@Auth User user, @ApiParam(required = true) CategoryModificationRequest req) {
public Response modifyCategory(@SecurityCheck User user, @ApiParam(required = true) CategoryModificationRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -381,7 +382,7 @@ public class CategoryREST {
@Path("/collapse")
@UnitOfWork
@ApiOperation(value = "Collapse a category", notes = "Save collapsed or expanded status for a category")
public Response collapse(@Auth User user, @ApiParam(required = true) CollapseRequest req) {
public Response collapse(@SecurityCheck User user, @ApiParam(required = true) CollapseRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -399,7 +400,7 @@ public class CategoryREST {
@Path("/unreadCount")
@UnitOfWork
@ApiOperation(value = "Get unread count for feed subscriptions", response = UnreadCount.class, responseContainer = "List")
public Response getUnreadCount(@Auth User user) {
public Response getUnreadCount(@SecurityCheck User user) {
Map<Long, UnreadCount> unreadCount = feedSubscriptionService.getUnreadCount(user);
return Response.ok(Lists.newArrayList(unreadCount.values())).build();
}
@@ -408,7 +409,7 @@ public class CategoryREST {
@Path("/get")
@UnitOfWork
@ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", response = Category.class)
public Response getSubscriptions(@Auth User user) {
public Response getSubscriptions(@SecurityCheck User user) {
Category root = cache.getUserRootCategory(user);
if (root == null) {
log.debug("tree cache miss for {}", user.getId());

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.List;
@@ -19,6 +18,7 @@ import com.commafeed.backend.dao.FeedEntryTagDAO;
import com.commafeed.backend.model.User;
import com.commafeed.backend.service.FeedEntryService;
import com.commafeed.backend.service.FeedEntryTagService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.request.MarkRequest;
import com.commafeed.frontend.model.request.MultipleMarkRequest;
import com.commafeed.frontend.model.request.StarRequest;
@@ -43,7 +43,7 @@ public class EntryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
public Response markFeedEntry(@Auth User user, @ApiParam(value = "Mark Request", required = true) MarkRequest req) {
public Response markFeedEntry(@SecurityCheck User user, @ApiParam(value = "Mark Request", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -55,7 +55,8 @@ public class EntryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark multiple feed entries", notes = "Mark feed entries as read/unread")
public Response markFeedEntries(@Auth User user, @ApiParam(value = "Multiple Mark Request", required = true) MultipleMarkRequest req) {
public Response markFeedEntries(@SecurityCheck User user,
@ApiParam(value = "Multiple Mark Request", required = true) MultipleMarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getRequests());
@@ -70,7 +71,7 @@ public class EntryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
public Response starFeedEntry(@Auth User user, @ApiParam(value = "Star Request", required = true) StarRequest req) {
public Response starFeedEntry(@SecurityCheck User user, @ApiParam(value = "Star Request", required = true) StarRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Preconditions.checkNotNull(req.getFeedId());
@@ -84,7 +85,7 @@ public class EntryREST {
@GET
@UnitOfWork
@ApiOperation(value = "Get list of tags for the user", notes = "Get list of tags for the user")
public Response getTags(@Auth User user) {
public Response getTags(@SecurityCheck User user) {
List<String> tags = feedEntryTagDAO.findByUser(user);
return Response.ok(tags).build();
}
@@ -93,7 +94,7 @@ public class EntryREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
public Response tagFeedEntry(@Auth User user, @ApiParam(value = "Tag Request", required = true) TagRequest req) {
public Response tagFeedEntry(@SecurityCheck User user, @ApiParam(value = "Tag Request", required = true) TagRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getEntryId());

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.io.InputStream;
@@ -57,6 +56,7 @@ import com.commafeed.backend.opml.OPMLExporter;
import com.commafeed.backend.opml.OPMLImporter;
import com.commafeed.backend.service.FeedEntryService;
import com.commafeed.backend.service.FeedSubscriptionService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.Entries;
import com.commafeed.frontend.model.Entry;
import com.commafeed.frontend.model.FeedInfo;
@@ -107,7 +107,7 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", response = Entries.class)
public Response getFeedEntries(
@Auth User user,
@SecurityCheck User user,
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@@ -172,7 +172,7 @@ public class FeedREST {
@ApiOperation(value = "Get feed entries as a feed", notes = "Get a feed of feed entries")
@Produces(MediaType.APPLICATION_XML)
public Response getFeedEntriesAsFeed(
@Auth User user,
@SecurityCheck(apiKeyAllowed = true) User user,
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@@ -234,7 +234,7 @@ public class FeedREST {
@Path("/fetch")
@UnitOfWork
@ApiOperation(value = "Fetch a feed", notes = "Fetch a feed by its url", response = FeedInfo.class)
public Response fetchFeed(@Auth User user, @ApiParam(value = "feed url", required = true) FeedInfoRequest req) {
public Response fetchFeed(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) FeedInfoRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getUrl());
@@ -252,7 +252,7 @@ public class FeedREST {
@GET
@UnitOfWork
@ApiOperation(value = "Queue all feeds of the user for refresh", notes = "Manually add all feeds of the user to the refresh queue")
public Response queueAllForRefresh(@Auth User user) {
public Response queueAllForRefresh(@SecurityCheck User user) {
feedSubscriptionService.refreshAll(user);
return Response.ok().build();
}
@@ -261,7 +261,7 @@ public class FeedREST {
@POST
@UnitOfWork
@ApiOperation(value = "Queue a feed for refresh", notes = "Manually add a feed to the refresh queue")
public Response queueForRefresh(@Auth User user, @ApiParam(value = "Feed id") IDRequest req) {
public Response queueForRefresh(@SecurityCheck User user, @ApiParam(value = "Feed id") IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -279,7 +279,7 @@ public class FeedREST {
@POST
@UnitOfWork
@ApiOperation(value = "Mark feed entries", notes = "Mark feed entries as read (unread is not supported)")
public Response markFeedEntries(@Auth User user, @ApiParam(value = "Mark request") MarkRequest req) {
public Response markFeedEntries(@SecurityCheck User user, @ApiParam(value = "Mark request") MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -296,7 +296,7 @@ public class FeedREST {
@Path("/get/{id}")
@UnitOfWork
@ApiOperation(value = "", notes = "")
public Response get(@Auth User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
public Response get(@SecurityCheck User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
FeedSubscription sub = feedSubscriptionDAO.findById(user, id);
@@ -311,7 +311,7 @@ public class FeedREST {
@Path("/favicon/{id}")
@UnitOfWork
@ApiOperation(value = "Fetch a feed's icon", notes = "Fetch a feed's icon")
public Response getFavicon(@Auth User user, @ApiParam(value = "subscription id") @PathParam("id") Long id) {
public Response getFavicon(@SecurityCheck User user, @ApiParam(value = "subscription id") @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
FeedSubscription subscription = feedSubscriptionDAO.findById(user, id);
@@ -348,7 +348,7 @@ public class FeedREST {
@Path("/subscribe")
@UnitOfWork
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
public Response subscribe(@Auth User user, @ApiParam(value = "subscription request", required = true) SubscribeRequest req) {
public Response subscribe(@SecurityCheck User user, @ApiParam(value = "subscription request", required = true) SubscribeRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getTitle());
Preconditions.checkNotNull(req.getUrl());
@@ -374,7 +374,7 @@ public class FeedREST {
@Path("/subscribe")
@UnitOfWork
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
public Response subscribe(@Auth User user, @ApiParam(value = "feed url", required = true) @QueryParam("url") String url) {
public Response subscribe(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) @QueryParam("url") String url) {
try {
Preconditions.checkNotNull(url);
@@ -401,7 +401,7 @@ public class FeedREST {
@Path("/unsubscribe")
@UnitOfWork
@ApiOperation(value = "Unsubscribe from a feed", notes = "Unsubscribe from a feed")
public Response unsubscribe(@Auth User user, @ApiParam(required = true) IDRequest req) {
public Response unsubscribe(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -417,7 +417,7 @@ public class FeedREST {
@Path("/modify")
@UnitOfWork
@ApiOperation(value = "Modify a subscription", notes = "Modify a feed subscription")
public Response modify(@Auth User user, @ApiParam(value = "subscription id", required = true) FeedModificationRequest req) {
public Response modify(@SecurityCheck User user, @ApiParam(value = "subscription id", required = true) FeedModificationRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -469,7 +469,7 @@ public class FeedREST {
@UnitOfWork
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(value = "OPML import", notes = "Import an OPML file, posted as a FORM with the 'file' name")
public Response importOpml(@Auth User user, @FormDataParam("file") InputStream input) {
public Response importOpml(@SecurityCheck User user, @FormDataParam("file") InputStream input) {
String publicUrl = config.getApplicationSettings().getPublicUrl();
if (StringUtils.isBlank(publicUrl)) {
@@ -495,7 +495,7 @@ public class FeedREST {
@UnitOfWork
@Produces(MediaType.APPLICATION_XML)
@ApiOperation(value = "OPML export", notes = "Export an OPML file of the user's subscriptions")
public Response exportOpml(@Auth User user) {
public Response exportOpml(@SecurityCheck User user) {
Opml opml = opmlExporter.export(user);
WireFeedOutput output = new WireFeedOutput();
String opmlString = null;

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import javax.ws.rs.Consumes;
@@ -20,6 +19,7 @@ import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.feed.FeedUtils;
import com.commafeed.backend.model.User;
import com.commafeed.backend.service.ApplicationPropertiesService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.ServerInfo;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
@@ -39,7 +39,7 @@ public class ServerREST {
@GET
@UnitOfWork
@ApiOperation(value = "Get server infos", notes = "Get server infos", response = ServerInfo.class)
public Response get(@Auth User user) {
public Response get(@SecurityCheck User user) {
ServerInfo infos = new ServerInfo();
infos.setAnnouncement(config.getApplicationSettings().getAnnouncement());
infos.setVersion(applicationPropertiesService.getVersion());
@@ -52,7 +52,7 @@ public class ServerREST {
@UnitOfWork
@ApiOperation(value = "proxy image")
@Produces("image/png")
public Response get(@Auth User user, @QueryParam("u") String url) {
public Response get(@SecurityCheck User user, @QueryParam("u") String url) {
if (!config.getApplicationSettings().isImageProxyEnabled()) {
return Response.status(Status.FORBIDDEN).build();
}

View File

@@ -1,6 +1,5 @@
package com.commafeed.frontend.resource;
import io.dropwizard.auth.Auth;
import io.dropwizard.hibernate.UnitOfWork;
import java.util.Arrays;
@@ -31,6 +30,7 @@ import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.backend.model.UserSettings.ViewMode;
import com.commafeed.backend.service.PasswordEncryptionService;
import com.commafeed.backend.service.UserService;
import com.commafeed.frontend.auth.SecurityCheck;
import com.commafeed.frontend.model.Settings;
import com.commafeed.frontend.model.UserModel;
import com.commafeed.frontend.model.request.ProfileModificationRequest;
@@ -57,7 +57,7 @@ public class UserREST {
@GET
@UnitOfWork
@ApiOperation(value = "Retrieve user settings", notes = "Retrieve user settings", response = Settings.class)
public Response getSettings(@Auth User user) {
public Response getSettings(@SecurityCheck User user) {
Settings s = new Settings();
UserSettings settings = userSettingsDAO.findByUser(user);
if (settings != null) {
@@ -111,7 +111,7 @@ public class UserREST {
@POST
@UnitOfWork
@ApiOperation(value = "Save user settings", notes = "Save user settings")
public Response saveSettings(@Auth User user, @ApiParam(required = true) Settings settings) {
public Response saveSettings(@SecurityCheck User user, @ApiParam(required = true) Settings settings) {
Preconditions.checkNotNull(settings);
UserSettings s = userSettingsDAO.findByUser(user);
@@ -149,7 +149,7 @@ public class UserREST {
@GET
@UnitOfWork
@ApiOperation(value = "Retrieve user's profile", response = UserModel.class)
public Response get(@Auth User user) {
public Response get(@SecurityCheck User user) {
UserModel userModel = new UserModel();
userModel.setId(user.getId());
userModel.setName(user.getName());
@@ -168,7 +168,7 @@ public class UserREST {
@POST
@UnitOfWork
@ApiOperation(value = "Save user's profile")
public Response save(@Auth User user, @ApiParam(required = true) ProfileModificationRequest request) {
public Response save(@SecurityCheck User user, @ApiParam(required = true) ProfileModificationRequest request) {
Preconditions.checkArgument(StringUtils.isBlank(request.getPassword()) || request.getPassword().length() >= 6);
if (StringUtils.isNotBlank(request.getEmail())) {
User u = userDAO.findByEmail(request.getEmail());
@@ -210,7 +210,7 @@ public class UserREST {
@POST
@UnitOfWork
@ApiOperation(value = "Delete the user account")
public Response delete(@Auth User user) {
public Response delete(@SecurityCheck User user) {
if (CommaFeedApplication.USERNAME_ADMIN.equals(user.getName()) || CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) {
return Response.status(Status.FORBIDDEN).build();
}