Last active
March 1, 2017 16:53
-
-
Save psamsotha/52bfc93a364c4920bf37d8c54630842b to your computer and use it in GitHub Desktop.
Jersey Entity Filtering with Security Annotations.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import com.fasterxml.jackson.databind.annotation.JsonSerialize; | |
| import org.glassfish.jersey.logging.LoggingFeature; | |
| import org.glassfish.jersey.message.filtering.SecurityEntityFilteringFeature; | |
| import org.glassfish.jersey.server.ResourceConfig; | |
| import org.glassfish.jersey.test.JerseyTest; | |
| import org.glassfish.jersey.test.TestProperties; | |
| import org.junit.Test; | |
| import javax.annotation.security.RolesAllowed; | |
| import javax.ws.rs.GET; | |
| import javax.ws.rs.NotAuthorizedException; | |
| import javax.ws.rs.Path; | |
| import javax.ws.rs.Produces; | |
| import javax.ws.rs.container.ContainerRequestContext; | |
| import javax.ws.rs.container.ContainerRequestFilter; | |
| import javax.ws.rs.container.PreMatching; | |
| import javax.ws.rs.core.SecurityContext; | |
| import javax.ws.rs.ext.Provider; | |
| import java.io.IOException; | |
| import java.security.Principal; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| import static org.hamcrest.CoreMatchers.is; | |
| import static org.hamcrest.MatcherAssert.assertThat; | |
| import static org.hamcrest.core.IsNull.nullValue; | |
| /** | |
| * Run like any other unit test. Only two required dependencies | |
| * | |
| * See Stack Overflow http://stackoverflow.com/q/42519571/2587435 | |
| * | |
| * <dependency> | |
| * <groupId>org.glassfish.jersey.test-framework.providers</groupId> | |
| * <artifactId>jersey-test-framework-provider-grizzly2</artifactId> | |
| * <version>${jersey2.version}</version> | |
| * </dependency> | |
| * <dependency> | |
| * <groupId>org.glassfish.jersey.media</groupId> | |
| * <artifactId>jersey-media-json-jackson</artifactId> | |
| * <version>${jersey2.version}</version> | |
| * </dependency> | |
| * | |
| * @author Paul Samsotha. | |
| */ | |
| public class SecurityFilteringTest extends JerseyTest { | |
| @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) | |
| public static class Model { | |
| private String global; | |
| private String secured; | |
| public Model() {} | |
| public Model(String global, String secured) { | |
| this.global = global; | |
| this.secured = secured; | |
| } | |
| public String getGlobal() { return this.global; } | |
| public void setGlobal(String global) { this.global = global; } | |
| @RolesAllowed({"ADMIN"}) | |
| public String getSecured() { return this.secured; } | |
| public void setSecured(String secured) {this.secured = secured; } | |
| } | |
| @Path("resource") | |
| public static class Resource { | |
| @GET | |
| @Produces("application/json") | |
| public Model get() { | |
| return new Model("global", "secured"); | |
| } | |
| } | |
| @Provider | |
| @PreMatching | |
| public static class SimpleAuthFilter implements ContainerRequestFilter { | |
| private static final Map<String, User> userStore = new ConcurrentHashMap<>(); | |
| static { | |
| userStore.put("peeskillet", new User("peeskillet", Arrays.asList("ADMIN", "USER"))); | |
| userStore.put("paulski", new User("paulski", Arrays.asList("USER"))); | |
| } | |
| @Override | |
| public void filter(ContainerRequestContext request) throws IOException { | |
| final String authHeader = request.getHeaderString("Authorization"); | |
| final String username = authHeader.split("=")[1]; | |
| final User user = userStore.get(username); | |
| if (user == null) { | |
| throw new NotAuthorizedException("No good."); | |
| } | |
| request.setSecurityContext(new SimpleSecurityContext(user)); | |
| } | |
| private static class SimpleSecurityContext implements SecurityContext { | |
| private final User user; | |
| SimpleSecurityContext(User user) { | |
| this.user = user; | |
| } | |
| @Override | |
| public Principal getUserPrincipal() { | |
| return new Principal() { | |
| @Override | |
| public String getName() { | |
| return user.getUsername(); | |
| } | |
| }; | |
| } | |
| @Override | |
| public boolean isUserInRole(String role) { | |
| return user.getRoles().contains(role); | |
| } | |
| @Override | |
| public boolean isSecure() { | |
| return false; | |
| } | |
| @Override | |
| public String getAuthenticationScheme() { | |
| return "simple"; | |
| } | |
| } | |
| private static class User { | |
| private String username; | |
| private List<String> roles; | |
| User(String username, List<String> roles) { | |
| this.username = username; | |
| this.roles = roles; | |
| } | |
| public String getUsername() { return this.username; } | |
| public List<String> getRoles() { return this.roles; } | |
| } | |
| } | |
| @Override | |
| public ResourceConfig configure() { | |
| enable(TestProperties.DUMP_ENTITY); | |
| enable(TestProperties.LOG_TRAFFIC); | |
| return new ResourceConfig() | |
| .register(SecurityEntityFilteringFeature.class) | |
| .register(SimpleAuthFilter.class) | |
| .register(Resource.class); | |
| } | |
| @Test | |
| public void getGlobalPropertiesOnly() { | |
| final Model model = target("resource") | |
| .request() | |
| .header("Authorization", "username=paulski") | |
| .get() | |
| .readEntity(Model.class); | |
| assertThat(model.getGlobal(), is("global")); | |
| assertThat(model.getSecured(), is(nullValue())); | |
| } | |
| @Test | |
| public void getGlobalWithAdminProperties() { | |
| final Model model = target("resource") | |
| .request() | |
| .header("Authorization", "username=peeskillet") | |
| .get() | |
| .readEntity(Model.class); | |
| assertThat(model.getGlobal(), is("global")); | |
| assertThat(model.getSecured(), is("secured")); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment