mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
added security checks
This commit is contained in:
@@ -16,7 +16,9 @@ import com.commafeed.backend.model.Feed;
|
|||||||
import com.commafeed.backend.model.FeedCategory;
|
import com.commafeed.backend.model.FeedCategory;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.backend.model.UserRole;
|
||||||
import com.commafeed.backend.security.PasswordEncryptionService;
|
import com.commafeed.backend.security.PasswordEncryptionService;
|
||||||
|
import com.commafeed.backend.security.Role;
|
||||||
|
|
||||||
@Startup
|
@Startup
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -48,6 +50,8 @@ public class StartupBean {
|
|||||||
User user = new User();
|
User user = new User();
|
||||||
byte[] salt = encryptionService.generateSalt();
|
byte[] salt = encryptionService.generateSalt();
|
||||||
user.setName("admin");
|
user.setName("admin");
|
||||||
|
user.getRoles().add(new UserRole(user, Role.ADMIN));
|
||||||
|
user.getRoles().add(new UserRole(user, Role.USER));
|
||||||
user.setSalt(salt);
|
user.setSalt(salt);
|
||||||
user.setPassword(encryptionService.getEncryptedPassword("admin",
|
user.setPassword(encryptionService.getEncryptedPassword("admin",
|
||||||
salt));
|
salt));
|
||||||
@@ -56,6 +60,7 @@ public class StartupBean {
|
|||||||
User testUser = new User();
|
User testUser = new User();
|
||||||
byte[] saltTest = encryptionService.generateSalt();
|
byte[] saltTest = encryptionService.generateSalt();
|
||||||
testUser.setName("test");
|
testUser.setName("test");
|
||||||
|
testUser.getRoles().add(new UserRole(testUser, Role.USER));
|
||||||
testUser.setSalt(saltTest);
|
testUser.setSalt(saltTest);
|
||||||
testUser.setPassword(encryptionService.getEncryptedPassword("test",
|
testUser.setPassword(encryptionService.getEncryptedPassword("test",
|
||||||
saltTest));
|
saltTest));
|
||||||
|
|||||||
23
src/main/java/com/commafeed/backend/dao/UserRoleService.java
Normal file
23
src/main/java/com/commafeed/backend/dao/UserRoleService.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.ejb.Stateless;
|
||||||
|
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.backend.model.UserRole;
|
||||||
|
import com.commafeed.frontend.utils.ModelFactory.MF;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
@Stateless
|
||||||
|
public class UserRoleService extends GenericDAO<UserRole, Long> {
|
||||||
|
|
||||||
|
public List<String> getRoles(User user) {
|
||||||
|
List<String> list = Lists.newArrayList();
|
||||||
|
for (UserRole role : findByField(MF.i(proxy().getUser()), user)) {
|
||||||
|
list.add(role.getRole());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
package com.commafeed.backend.model;
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "USERS")
|
@Table(name = "USERS")
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
@@ -18,6 +24,9 @@ public class User extends AbstractModel {
|
|||||||
@Column(length = 8)
|
@Column(length = 8)
|
||||||
private byte[] salt;
|
private byte[] salt;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST)
|
||||||
|
private Set<UserRole> roles = Sets.newHashSet();
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -42,4 +51,12 @@ public class User extends AbstractModel {
|
|||||||
this.salt = salt;
|
this.salt = salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<UserRole> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(Set<UserRole> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/main/java/com/commafeed/backend/model/UserRole.java
Normal file
46
src/main/java/com/commafeed/backend/model/UserRole.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "USERROLES")
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class UserRole extends AbstractModel {
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@Column(name = "roleName")
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
public UserRole() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRole(User user, String role) {
|
||||||
|
this.user = user;
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.commafeed.frontend.pages.auth;
|
package com.commafeed.backend.security;
|
||||||
|
|
||||||
public class Role {
|
public class Role {
|
||||||
public static final String USER = "user";
|
public static final String USER = "user";
|
||||||
@@ -9,7 +9,7 @@ import org.apache.wicket.request.Request;
|
|||||||
|
|
||||||
import com.commafeed.backend.dao.UserService;
|
import com.commafeed.backend.dao.UserService;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
import com.commafeed.frontend.pages.auth.Role;
|
import com.commafeed.backend.security.Role;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class CommaFeedSession extends AuthenticatedWebSession {
|
public class CommaFeedSession extends AuthenticatedWebSession {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import org.apache.wicket.markup.head.CssHeaderItem;
|
|||||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||||
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
||||||
|
|
||||||
import com.commafeed.frontend.pages.auth.Role;
|
import com.commafeed.backend.security.Role;
|
||||||
import com.commafeed.frontend.references.angular.AngularReference;
|
import com.commafeed.frontend.references.angular.AngularReference;
|
||||||
import com.commafeed.frontend.references.angular.AngularResourceReference;
|
import com.commafeed.frontend.references.angular.AngularResourceReference;
|
||||||
import com.commafeed.frontend.references.angular.AngularSanitizeReference;
|
import com.commafeed.frontend.references.angular.AngularSanitizeReference;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import com.google.gson.JsonSerializationContext;
|
|||||||
import com.google.gson.JsonSerializer;
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
@Provider
|
@Provider
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN })
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class JSONMessageBodyReaderWriter implements MessageBodyWriter<Object>,
|
public class JSONMessageBodyReaderWriter implements MessageBodyWriter<Object>,
|
||||||
MessageBodyReader<Object> {
|
MessageBodyReader<Object> {
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
package com.commafeed.frontend.rest;
|
package com.commafeed.frontend.rest;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.ws.rs.ApplicationPath;
|
import javax.ws.rs.ApplicationPath;
|
||||||
import javax.ws.rs.core.Application;
|
import javax.ws.rs.core.Application;
|
||||||
|
|
||||||
import com.commafeed.frontend.rest.resources.EntriesREST;
|
|
||||||
import com.commafeed.frontend.rest.resources.SettingsREST;
|
|
||||||
import com.commafeed.frontend.rest.resources.SubscriptionsREST;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
@ApplicationPath("/rest")
|
@ApplicationPath("/rest")
|
||||||
public class RESTApplication extends Application {
|
public class RESTApplication extends Application {
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Class<?>> getClasses() {
|
|
||||||
Set<Class<?>> set = Sets.newHashSet();
|
|
||||||
set.add(JSONMessageBodyReaderWriter.class);
|
|
||||||
|
|
||||||
set.add(SubscriptionsREST.class);
|
|
||||||
set.add(EntriesREST.class);
|
|
||||||
set.add(SettingsREST.class);
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/main/java/com/commafeed/frontend/rest/SecurityCheck.java
Normal file
23
src/main/java/com/commafeed/frontend/rest/SecurityCheck.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package com.commafeed.frontend.rest;
|
||||||
|
|
||||||
|
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.enterprise.util.Nonbinding;
|
||||||
|
import javax.interceptor.InterceptorBinding;
|
||||||
|
|
||||||
|
@Inherited
|
||||||
|
@InterceptorBinding
|
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SecurityCheck {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roles needed.
|
||||||
|
*/
|
||||||
|
@Nonbinding
|
||||||
|
String[] value() default {};
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.commafeed.frontend.rest.resources;
|
package com.commafeed.frontend.rest.resources;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.interceptor.AroundInvoke;
|
||||||
|
import javax.interceptor.InvocationContext;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
@@ -9,7 +14,7 @@ import javax.ws.rs.Produces;
|
|||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.apache.wicket.ThreadContext;
|
import org.apache.wicket.ThreadContext;
|
||||||
import org.apache.wicket.authentication.IAuthenticationStrategy;
|
import org.apache.wicket.authentication.IAuthenticationStrategy;
|
||||||
@@ -22,15 +27,19 @@ import com.commafeed.backend.dao.FeedEntryService;
|
|||||||
import com.commafeed.backend.dao.FeedEntryStatusService;
|
import com.commafeed.backend.dao.FeedEntryStatusService;
|
||||||
import com.commafeed.backend.dao.FeedService;
|
import com.commafeed.backend.dao.FeedService;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionService;
|
import com.commafeed.backend.dao.FeedSubscriptionService;
|
||||||
|
import com.commafeed.backend.dao.UserRoleService;
|
||||||
import com.commafeed.backend.dao.UserService;
|
import com.commafeed.backend.dao.UserService;
|
||||||
import com.commafeed.backend.dao.UserSettingsService;
|
import com.commafeed.backend.dao.UserSettingsService;
|
||||||
import com.commafeed.backend.feeds.OPMLImporter;
|
import com.commafeed.backend.feeds.OPMLImporter;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.backend.security.Role;
|
||||||
import com.commafeed.frontend.CommaFeedApplication;
|
import com.commafeed.frontend.CommaFeedApplication;
|
||||||
import com.commafeed.frontend.CommaFeedSession;
|
import com.commafeed.frontend.CommaFeedSession;
|
||||||
|
import com.commafeed.frontend.rest.SecurityCheck;
|
||||||
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@SecurityCheck(Role.USER)
|
||||||
public abstract class AbstractREST {
|
public abstract class AbstractREST {
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
@@ -60,6 +69,9 @@ public abstract class AbstractREST {
|
|||||||
@Inject
|
@Inject
|
||||||
UserSettingsService userSettingsService;
|
UserSettingsService userSettingsService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserRoleService userRoleService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
OPMLImporter opmlImporter;
|
OPMLImporter opmlImporter;
|
||||||
|
|
||||||
@@ -80,14 +92,46 @@ public abstract class AbstractREST {
|
|||||||
session.signIn(data[0], data[1]);
|
session.signIn(data[0], data[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getUser() == null) {
|
|
||||||
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected User getUser() {
|
protected User getUser() {
|
||||||
return CommaFeedSession.get().getUser();
|
return CommaFeedSession.get().getUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AroundInvoke
|
||||||
|
public Object checkSecurity(InvocationContext context) throws Exception {
|
||||||
|
User user = getUser();
|
||||||
|
if (user == null) {
|
||||||
|
throw new WebApplicationException(Status.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean allowed = false;
|
||||||
|
Method method = context.getMethod();
|
||||||
|
|
||||||
|
if (method.isAnnotationPresent(SecurityCheck.class)) {
|
||||||
|
allowed = checkRole(user, method.getAnnotation(SecurityCheck.class));
|
||||||
|
} else if (method.getDeclaringClass().isAnnotationPresent(
|
||||||
|
SecurityCheck.class)) {
|
||||||
|
allowed = checkRole(
|
||||||
|
user,
|
||||||
|
method.getDeclaringClass().getAnnotation(
|
||||||
|
SecurityCheck.class));
|
||||||
|
}
|
||||||
|
if (!allowed) {
|
||||||
|
throw new WebApplicationException(Status.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkRole(User user, SecurityCheck annotation) {
|
||||||
|
List<String> roles = userRoleService.getRoles(user);
|
||||||
|
for (String role : annotation.value()) {
|
||||||
|
if (!roles.contains(role)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:weld="http://jboss.org/schema/weld/beans"
|
|
||||||
xsi:schemaLocation="
|
xsi:schemaLocation="
|
||||||
http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd
|
http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd
|
||||||
http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd">
|
http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd">
|
||||||
|
|
||||||
<weld:scan>
|
|
||||||
<weld:include name="**" />
|
|
||||||
</weld:scan>
|
|
||||||
</beans>
|
</beans>
|
||||||
Reference in New Issue
Block a user