Commit 3e533eefbbc9c3470508be11fcd0c69fc6d10c78

Authored by Thomas Ziemer
1 parent 32cb9414

feature: SecurityInterceptor eingebaut

... ... @@ -14,7 +14,8 @@
14 14 <mvn-compiler-plugin-version>3.3</mvn-compiler-plugin-version>
15 15 <jee-version>7.0</jee-version>
16 16 <java-version>1.8</java-version>
17   - <jaxrs-version>2.0</jaxrs-version>
  17 + <jaxrs-version>2.0.1</jaxrs-version>
  18 + <resteasy-version>3.1.3.Final</resteasy-version>
18 19 <mysql-version>5.1.41</mysql-version>
19 20 <hibernate-version>5.2.1.Final</hibernate-version>
20 21 <junit-version>4.12</junit-version>
... ... @@ -45,6 +46,12 @@
45 46 <version>${jaxrs-version}</version>
46 47 <scope>provided</scope>
47 48 </dependency>
  49 + <dependency>
  50 + <groupId>org.jboss.resteasy</groupId>
  51 + <artifactId>resteasy-jaxrs</artifactId>
  52 + <version>${resteasy-version}</version>
  53 + <scope>provided</scope>
  54 + </dependency>
48 55 <dependency>
49 56 <groupId>junit</groupId>
50 57 <artifactId>junit</artifactId>
... ...
src/main/java/net/ziemers/swxercise/lg/user/service/UserService.java
1 1 package net.ziemers.swxercise.lg.user.service;
2 2  
3 3 import java.util.Collection;
  4 +import java.util.Set;
4 5  
5 6 import javax.ejb.Stateless;
6 7 import javax.inject.Inject;
... ... @@ -22,23 +23,50 @@ public class UserService {
22 23 @Inject
23 24 private SessionContext sessionContext;
24 25  
  26 + /**
  27 + * Meldet den Benutzer im SessionContext an.
  28 + *
  29 + * @param dto das {@link UserDto} enthält die Eigenschaften des anzumeldenden Benutzers
  30 + * @return <code>true</code>, wenn die Anmeldung erfolgreich war.
  31 + */
25 32 public boolean loginUser(UserDto dto) {
26 33 final User user = dao.findByUsername(dto.getUsername());
27 34 return user != null && user.getProfile().isValidPassword(dto.getPassword()) && sessionContext.login(user);
28 35 }
29 36  
  37 + /**
  38 + * Meldet den Benutzer vom SessionContext ab.
  39 + *
  40 + * @return <code>true</code>, wenn die Abmeldung erfolgreich war.
  41 + */
30 42 public boolean logoutUser() {
31   - return sessionContext.logout();
  43 + return sessionContext.logout();
32 44 }
33 45  
  46 + /**
  47 + * Findet den Benutzer mit der übergebenen Id.
  48 + *
  49 + * @param id die Id des gesuchten Benutzes.
  50 + * @return den gesuchten Benutzer, oder <code>null</code>, falls ein solcher nicht existiert.
  51 + */
34 52 public User findUser(final Long id) {
35 53 return dao.findById(id);
36 54 }
37 55  
  56 + /**
  57 + * Findet alle existierenden Benutzer.
  58 + * @return alle Benutzer, oder eine leere Collection, falls keine existieren.
  59 + */
38 60 public Collection<User> findAllUsers() {
39 61 return dao.findAll(User.class);
40 62 }
41 63  
  64 + /**
  65 + * Erstellt einen neuen Benutzer, sofern noch keiner mit dem selben Benutzernamen existiert.
  66 + *
  67 + * @param userDto das {@link UserDto} enthält die Eigenschaften des zu erstellenden Benutzers
  68 + * @return die Id des neuen Benutzers, wenn die Erstellung erfolgreich war.
  69 + */
42 70 public Long createUser(final UserDto userDto) {
43 71 User user = dao.findByUsername(userDto.getUsername());
44 72 if (user == null) {
... ... @@ -53,21 +81,48 @@ public class UserService {
53 81 return null;
54 82 }
55 83  
56   - public void deleteUser(final Long id) {
57   - dao.remove(User.class, id);
  84 + /**
  85 + * Löscht den Benutzer mit der übergebenen Id.
  86 + *
  87 + * @param id die Id des zu löschenden Benutzers
  88 + */
  89 + public User deleteUser(final Long id) {
  90 + return dao.remove(User.class, id);
58 91 }
59 92  
  93 + /**
  94 + * Löscht den zurzeit angemeldeten Benutzer.
  95 + *
  96 + * @return <code>true</code>, wenn das Löschen des angemeldeten Benutzers erfolgreich war.
  97 + */
60 98 public boolean deleteUser() {
61 99 // ist zurzeit ein Benutzer angemeldet, können wir ihn löschen
62 100 final User user = sessionContext.getUser();
63   - if (user != null) {
64   - return dao.remove(User.class, user.getId()) != null;
65   - }
66   - return false;
  101 + return user != null && dao.remove(User.class, user.getId()) != null;
67 102 }
68 103  
  104 + /**
  105 + * Liefert das {@link User}-Objekt des zurzeit angemeldeten Benutzers zurück.
  106 + * @return das User-Objekt des zurzeit angemeldeten Benutzers.
  107 + */
69 108 public User getSessionUser() {
70 109 return sessionContext.getUser();
71 110 }
72 111  
  112 + /**
  113 + * Prüft, ob der zurzeit angemeldete Benutzer eine Rolle aus der Liste der übergebenen Rollen besitzt.
  114 + *
  115 + * @param rolesSet die Rollenliste
  116 + * @return <code>true</code>, falls der zurzeit angemeldete Benutzer eine der übergebenen Rollen besitzt.
  117 + */
  118 + public boolean isUserAllowed(final Set<String> rolesSet) {
  119 + final User user = getSessionUser();
  120 +
  121 + // ist überhaupt ein Benutzer angemeldet?
  122 + if (user != null) {
  123 + // TODO muss noch implementiert werden
  124 + return true;
  125 + }
  126 + return false;
  127 + }
73 128 }
... ...
src/main/java/net/ziemers/swxercise/ui/SecurityInterceptor.java 0 → 100644
  1 +package net.ziemers.swxercise.ui;
  2 +
  3 +import javax.annotation.PostConstruct;
  4 +import javax.annotation.security.DenyAll;
  5 +import javax.annotation.security.PermitAll;
  6 +import javax.annotation.security.RolesAllowed;
  7 +import javax.inject.Inject;
  8 +import javax.ws.rs.container.ContainerRequestContext;
  9 +import javax.ws.rs.container.ContainerRequestFilter;
  10 +import javax.ws.rs.ext.Provider;
  11 +import java.lang.reflect.AnnotatedElement;
  12 +import java.util.Arrays;
  13 +import java.util.HashSet;
  14 +import java.util.Set;
  15 +
  16 +import net.ziemers.swxercise.lg.user.service.UserService;
  17 +import org.jboss.resteasy.core.Headers;
  18 +import org.jboss.resteasy.core.ResourceMethodInvoker;
  19 +import org.jboss.resteasy.core.ServerResponse;
  20 +import org.slf4j.Logger;
  21 +import org.slf4j.LoggerFactory;
  22 +
  23 +/**
  24 + * Dies ist ein Interceptor für die Annotationen @PermitAll, @DenyAll und @RolesAllowed. Er stellt sicher,
  25 + * dass die REST-Methoden, welche mit den genannten Annotationen versehen wurden, nur von authorisierten
  26 + * Benutzern aufgerufen werden können.
  27 + */
  28 +@Provider
  29 +public class SecurityInterceptor implements ContainerRequestFilter {
  30 +
  31 + private static final String PROPERTY_RMI = "org.jboss.resteasy.core.ResourceMethodInvoker";
  32 +
  33 + // 401: The request has not been applied because it lacks valid authentication credentials for the target resource.
  34 + private static final ServerResponse ACCESS_DENIED = new ServerResponse("Access denied for this rest method", 401, new Headers<>());
  35 +
  36 + // 403: The server understood the request but refuses to authorize it.
  37 + private static final ServerResponse ACCESS_FORBIDDEN = new ServerResponse("Nobody can access this rest method", 403, new Headers<>());
  38 +
  39 + private Logger logger;
  40 +
  41 + @Inject
  42 + private UserService userService;
  43 +
  44 + @PostConstruct
  45 + public void initialize() {
  46 + logger = LoggerFactory.getLogger(SecurityInterceptor.class);
  47 + }
  48 +
  49 + @Override
  50 + public void filter(ContainerRequestContext requestContext) {
  51 + final ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) requestContext.getProperty(PROPERTY_RMI);
  52 + final AnnotatedElement element = methodInvoker.getMethod();
  53 +
  54 + // Zugriff auf die Methode ist für alle erlaubt (obsolet)
  55 + if (element.isAnnotationPresent(PermitAll.class)) {
  56 + logger.debug("@PermitAll");
  57 + }
  58 +
  59 + // Zugriff auf die Methode ist für niemanden erlaubt
  60 + else if (element.isAnnotationPresent(DenyAll.class)) {
  61 + requestContext.abortWith(ACCESS_FORBIDDEN);
  62 + logger.debug("@DenyAll");
  63 + }
  64 +
  65 + // Zugriff auf die Methode muss anhand ihrer Rollen geprüft werden
  66 + else if (element.isAnnotationPresent(RolesAllowed.class)) {
  67 + final RolesAllowed rolesAllowed = element.getAnnotation(RolesAllowed.class);
  68 + final Set<String> rolesSet = new HashSet<>(Arrays.asList(rolesAllowed.value()));
  69 +
  70 + if (!userService.isUserAllowed(rolesSet)) {
  71 + requestContext.abortWith(ACCESS_DENIED);
  72 + }
  73 + logger.debug("@RolesAllowed({})", rolesSet.toString());
  74 + }
  75 + }
  76 +
  77 +}
... ...
src/main/java/net/ziemers/swxercise/ui/UserViewController.java
... ... @@ -2,6 +2,7 @@ package net.ziemers.swxercise.ui;
2 2  
3 3 import java.util.Collection;
4 4  
  5 +import javax.annotation.security.RolesAllowed;
5 6 import javax.enterprise.context.ApplicationScoped;
6 7 import javax.inject.Inject;
7 8 import javax.ws.rs.*;
... ... @@ -70,6 +71,7 @@ public class UserViewController {
70 71 @Path("v1/user")
71 72 @Consumes(MediaType.APPLICATION_JSON)
72 73 @Produces(MediaType.APPLICATION_JSON)
  74 + @RolesAllowed("ADMIN")
73 75 public RestResponse createUser(UserDto dto) {
74 76 final Long id = userService.createUser(dto);
75 77 if (id != null) {
... ... @@ -94,6 +96,7 @@ public class UserViewController {
94 96 @Path("v1/user/{id}")
95 97 @Consumes(MediaType.APPLICATION_JSON)
96 98 @Produces(MediaType.APPLICATION_JSON)
  99 + @RolesAllowed("ADMIN")
97 100 public RestResponse updateUser(@PathParam("id") Long id, UserDto dto) {
98 101 // TODO noch zu implementieren
99 102 return new RestResponse(ResponseState.FAILED);
... ... @@ -111,6 +114,7 @@ public class UserViewController {
111 114 @DELETE
112 115 @Path("v1/user/{id}")
113 116 @Produces(MediaType.APPLICATION_JSON)
  117 + @RolesAllowed("ADMIN")
114 118 public RestResponse deleteUser(@PathParam("id") Long id) {
115 119 userService.deleteUser(id);
116 120 return new RestResponse();
... ...