├── .gitignore ├── README.md ├── build.gradle ├── config.yml ├── go └── src ├── main └── java │ └── com │ └── example │ ├── ExampleConfiguration.java │ ├── ExampleService.java │ ├── core │ └── User.java │ ├── resources │ └── UserResource.java │ └── security │ ├── ExampleAuthenticator.java │ ├── ExampleCredentials.java │ └── ExampleSecurityProvider.java └── test ├── java └── com │ └── example │ ├── core │ └── UserTests.java │ ├── resources │ └── UserResourceTests.java │ └── security │ ├── ExampleAuthenticatorTests.java │ ├── ExampleCredentialsTests.java │ └── ExampleSecurityProviderTests.java └── resources └── fixtures └── user.json /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | out 3 | target 4 | .idea 5 | .idea_modules 6 | .gradle 7 | logs 8 | .DS_Store 9 | *.iml 10 | *.ipr 11 | *.iws 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dropwizard Security 2 | 3 | Sample application showing how to use security providers in your Dropwizard application. 4 | 5 | Includes an example custom security provider which can be injected into your service and used in Resource methods to 6 | authenticate requests and apply authorisation. Can be extended to implement a full authentication and authorisation for 7 | the service. 8 | 9 | ## Setup 10 | 11 | To compile: 12 | 13 | ``` 14 | gradle oneJar 15 | ``` 16 | 17 | To run: 18 | 19 | ``` 20 | java -jar build/libs/dropwizard-security-standalone.jar server config.yml 21 | ``` 22 | 23 | To test: 24 | 25 | ``` 26 | gradle test 27 | ``` 28 | 29 | ## Introduction 30 | 31 | The majority of the provider in this sample project was based off the [BasicAuthProvider](https://dropwizard.github.io/dropwizard/manual/auth.html) from Dropwizard auth library, I 32 | wanted to do this to understand better how the injectable security provider works and figure out how it could be used to 33 | implement authentication and authorisation. 34 | 35 | Also wanted to ensure I could easily extend and test any resources using the security, as the overhead for a security 36 | system is important in keeping your code clean and not obscuring the intended purpose with security code. 37 | 38 | ## Details 39 | 40 | Implementing the custom security provider requires three classes (in com.example.security): 41 | 42 | * [ExampleCredentials](https://github.com/stevenalexander/dropwizard-security/blob/master/src/main/java/com/example/security/ExampleCredentials.java) 43 | 44 | Holds the credentials extracted from the request, e.g. username/password or a token from a cookie. 45 | 46 | * [ExampleAuthenticator](https://github.com/stevenalexander/dropwizard-security/blob/master/src/main/java/com/example/security/ExampleAuthenticator.java) 47 | 48 | Takes the credentials and authenticates them, returning a principle (user) object, throwing an 49 | AuthenticationException if the credentials are invalid. 50 | 51 | * [ExampleSecurityProvider](https://github.com/stevenalexander/dropwizard-security/blob/master/src/main/java/com/example/security/ExampleSecurityProvider.java) 52 | 53 | Is injected into the service so any request decorated with the Dropwizard Auth attribute will be handled by this provider. 54 | Extracts credentials from requests, uses an authenticator to check them and throws WebExceptions if not authenticated. 55 | 56 | ``` 57 | /** 58 | * An example security provider that will look at each request when received by an endpoint using the auth attribute 59 | * and check that it has a header value containing a token and will authenticate the token to get the Principle (User) 60 | * for the request (otherwise throw an AuthenticationException). That Principle is the authenticated User associated 61 | * with the request and the resource method handling the request can use it to check authorisation to perform actions. 62 | * 63 | * @param The Principle class (User) to be returned when a request is authenticated 64 | */ 65 | public class ExampleSecurityProvider implements InjectableProvider { 66 | ... 67 | public ExampleSecurityProvider(Authenticator authenticator) { 68 | this.authenticator = authenticator; 69 | } 70 | ... 71 | private static class ExampleSecurityInjectable extends AbstractHttpContextInjectable { 72 | ... 73 | @Override 74 | public T getValue(HttpContext c) { 75 | // This is where the credentials are extracted from the request 76 | final String header = c.getRequest().getHeaderValue(CUSTOM_HEADER); 77 | try { 78 | if (header != null) { 79 | final Optional result = authenticator.authenticate(new ExampleCredentials(header)); 80 | if (result.isPresent()) { 81 | return result.get(); 82 | } 83 | } 84 | } catch (AuthenticationException e) { 85 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 86 | } 87 | 88 | if (required) { 89 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 90 | } 91 | 92 | return null; 93 | } 94 | } 95 | ``` 96 | 97 | The security provider is injected into the service in the Service class. 98 | 99 | ``` 100 | public class ExampleService extends com.yammer.dropwizard.Service { 101 | ... 102 | @Override 103 | public void run(ExampleConfiguration configuration, Environment environment) throws Exception { 104 | environment.addResource(new UserResource()); 105 | 106 | // Adds security provider so resource methods decorated with auth attribute will use this authenticator 107 | environment.addProvider(new ExampleSecurityProvider(new ExampleAuthenticator())); 108 | } 109 | ``` 110 | 111 | Resources using authentication just add the Auth attribute to their method signature. 112 | 113 | ``` 114 | @Path("/user") 115 | @Consumes({MediaType.APPLICATION_JSON}) 116 | @Produces({MediaType.APPLICATION_JSON}) 117 | public class UserResource { 118 | ... 119 | /* 120 | * Using the Auth attribute will use the injected provider to authenticate all requests to this path 121 | * You can also use the principal to apply authorisation in code dynamically 122 | */ 123 | @GET 124 | public List getAll(@Auth User principal){ 125 | 126 | if (!principal.getDisplayRole().equals(User.ROLE_ADMIN)) { 127 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 128 | } 129 | ... 130 | ``` 131 | 132 | Testing the resources requires injecting a provider into the test service (note, I used the full one but for simplicity 133 | you can inject a mock which would return a controllable principal). 134 | 135 | ``` 136 | public class UserResourceTests extends ResourceTest { 137 | ... 138 | @Override 139 | protected void setUpResources() { 140 | addResource(new UserResource()); 141 | 142 | // Need to add SecurityProvider to all resource tests for resources using Auth, or you get 415 response 143 | // you can inject the authenticator to mock authentication results while ensuring you test true to how 144 | // the call will be made 145 | final ExampleAuthenticator authenticator = new ExampleAuthenticator(); 146 | addProvider(new ExampleSecurityProvider<>(authenticator)); 147 | } 148 | 149 | @Test 150 | public void getAll() throws Exception { 151 | List users = client().resource("/user") 152 | .header(ExampleSecurityProvider.CUSTOM_HEADER, "validAdminToken") 153 | .get(new GenericType>() {}); 154 | assertEquals(2, users.size()); 155 | assertEquals("user1", users.get(0).getUsername()); 156 | } 157 | 158 | @Test 159 | public void getAllThrows401WhenNotAuthenticatedToken() throws Exception { 160 | try { 161 | client().resource("/user") 162 | .get(new GenericType>() {}); 163 | 164 | fail("Should have thrown 401"); 165 | } catch (UniformInterfaceException ex) { 166 | assertEquals(ex.getResponse().getStatus(), 401); 167 | } 168 | } 169 | ... 170 | ``` 171 | 172 | ## Conclusion 173 | 174 | Using the injectable security provider you can implement an extremely flexible authentication and authorisation system 175 | in your service, while keeping the code overhead in your resource methods and tests minimal via the Auth attributes. In 176 | terms of simplicity it blows away a lot of security libraries I've worked with for other frameworks. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'gradle-one-jar' 3 | apply plugin: 'application' 4 | apply plugin: 'idea' 5 | 6 | // Use Java 7 by default 7 | sourceCompatibility = '1.7' 8 | targetCompatibility = '1.7' 9 | 10 | // UTF-8 should be standard by now. So use it! 11 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' 12 | 13 | // The main class of the application 14 | mainClassName = 'com.example.ExampleService' 15 | 16 | // Add Gradle OneJar Plugin, see https://github.com/rholder/gradle-one-jar 17 | buildscript { 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | classpath 'com.github.rholder:gradle-one-jar:1.0.3' 24 | } 25 | } 26 | 27 | // Set our project variables 28 | project.ext { 29 | dropwizardVersion = '0.6.2' 30 | jerseyVersion = '1.17.1' 31 | } 32 | 33 | repositories { 34 | mavenCentral() 35 | } 36 | 37 | dependencies { 38 | compile ( 39 | 'com.yammer.dropwizard:dropwizard-core:' + dropwizardVersion, 40 | 'com.yammer.dropwizard:dropwizard-auth:' + dropwizardVersion, 41 | 'com.sun.jersey:jersey-client:' + jerseyVersion 42 | ) 43 | testCompile ( 44 | 'com.yammer.dropwizard:dropwizard-testing:' + dropwizardVersion 45 | ) 46 | } 47 | 48 | // Configure the oneJar task 49 | task oneJar(type: OneJar) { 50 | mainClass = mainClassName 51 | } 52 | 53 | // Configure the run task to start the Dropwizard service 54 | run { 55 | args 'server', './config.yml' 56 | 57 | } 58 | 59 | task wrapper(type: Wrapper) { 60 | gradleVersion = '1.4' 61 | } 62 | 63 | artifacts { 64 | oneJar 65 | } 66 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | http: 2 | rootPath: "/*" 3 | port: 9050 4 | adminPort: 9051 5 | -------------------------------------------------------------------------------- /go: -------------------------------------------------------------------------------- 1 | gradle oneJar 2 | java -jar build/libs/dropwizard-security-standalone.jar server config.yml 3 | -------------------------------------------------------------------------------- /src/main/java/com/example/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.yammer.dropwizard.config.Configuration; 4 | 5 | public class ExampleConfiguration extends com.yammer.dropwizard.config.Configuration { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/example/ExampleService.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.example.core.User; 4 | import com.example.resources.UserResource; 5 | 6 | import com.example.security.ExampleAuthenticator; 7 | import com.example.security.ExampleSecurityProvider; 8 | import com.yammer.dropwizard.config.Bootstrap; 9 | import com.yammer.dropwizard.config.Configuration; 10 | import com.yammer.dropwizard.config.Environment; 11 | 12 | public class ExampleService extends com.yammer.dropwizard.Service { 13 | 14 | public static void main(String[] args) throws Exception 15 | { 16 | new com.example.ExampleService().run(args); 17 | } 18 | 19 | @Override 20 | public void initialize(Bootstrap bootstrap) { 21 | bootstrap.setName("dropwizard-security"); 22 | } 23 | 24 | @Override 25 | public void run(ExampleConfiguration configuration, Environment environment) throws Exception { 26 | environment.addResource(new UserResource()); 27 | 28 | // Adds security provider so resource methods decorated with auth attribute will use this authenticator 29 | environment.addProvider(new ExampleSecurityProvider(new ExampleAuthenticator())); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/example/core/User.java: -------------------------------------------------------------------------------- 1 | package com.example.core; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import org.hibernate.validator.constraints.NotEmpty; 5 | 6 | import javax.validation.constraints.NotNull; 7 | 8 | public class User { 9 | 10 | public static final String ROLE_ADMIN = "admin"; 11 | public static final String ROLE_EDITOR = "editor"; 12 | 13 | @NotEmpty 14 | @JsonProperty 15 | private String username; 16 | 17 | @NotEmpty 18 | @JsonProperty 19 | private String password; 20 | 21 | @NotEmpty 22 | @JsonProperty 23 | private String displayName; 24 | 25 | @NotEmpty 26 | @JsonProperty 27 | private String displayRole; 28 | 29 | public String getUsername() { 30 | return username; 31 | } 32 | 33 | public User setUsername(String username) { 34 | this.username = username; 35 | return this; 36 | } 37 | 38 | public String getPassword() { 39 | return password; 40 | } 41 | 42 | public User setPassword(String password) { 43 | this.password = password; 44 | return this; 45 | } 46 | 47 | public String getDisplayName() { 48 | return displayName; 49 | } 50 | 51 | public User setDisplayName(String displayName) { 52 | this.displayName = displayName; 53 | return this; 54 | } 55 | 56 | public String getDisplayRole() { 57 | return displayRole; 58 | } 59 | 60 | public User setDisplayRole(String displayRole) { 61 | this.displayRole = displayRole; 62 | return this; 63 | } 64 | 65 | @Override 66 | public boolean equals(Object o) { 67 | if (this == o) return true; 68 | if (!(o instanceof User)) return false; 69 | 70 | User that = (User) o; 71 | 72 | if (!getUsername().equals(that.getUsername())) return false; 73 | if (!getPassword().equals(that.getPassword())) return false; 74 | if (!getDisplayName().equals(that.getDisplayName())) return false; 75 | if (!getDisplayRole().equals(that.getDisplayRole())) return false; 76 | 77 | return true; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/example/resources/UserResource.java: -------------------------------------------------------------------------------- 1 | package com.example.resources; 2 | 3 | import com.example.core.User; 4 | import com.yammer.dropwizard.auth.Auth; 5 | 6 | import javax.validation.Valid; 7 | import javax.ws.rs.*; 8 | import javax.ws.rs.core.MediaType; 9 | import javax.ws.rs.core.Response; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | 13 | @Path("/user") 14 | @Consumes({MediaType.APPLICATION_JSON}) 15 | @Produces({MediaType.APPLICATION_JSON}) 16 | public class UserResource { 17 | 18 | public UserResource() { 19 | super(); 20 | } 21 | 22 | /* 23 | * Using the Auth attribute will use the injected provider to authenticate all requests to this path 24 | * You can also use the principal to apply authorisation in code dynamically 25 | */ 26 | @GET 27 | public List getAll(@Auth User principal){ 28 | 29 | if (!principal.getDisplayRole().equals(User.ROLE_ADMIN)) { 30 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 31 | } 32 | 33 | List users = new LinkedList<>(); 34 | users.add( 35 | new User() 36 | .setUsername("user1") 37 | .setDisplayName("User 1") 38 | .setDisplayRole("Admin") 39 | ); 40 | users.add( 41 | new User() 42 | .setUsername("user2") 43 | .setDisplayName("User 2") 44 | .setDisplayRole("DBA") 45 | ); 46 | 47 | return users; 48 | } 49 | 50 | @GET 51 | @Path("/{username}") 52 | public User get(@PathParam("username") String username){ 53 | return new User() 54 | .setUsername(username) 55 | .setDisplayName(username) 56 | .setDisplayRole("DBA"); 57 | } 58 | 59 | @POST 60 | public User add(@Valid User user) { 61 | return user; 62 | } 63 | 64 | @PUT 65 | @Path("/{username}") 66 | public User update(@PathParam("username") String username, @Valid User user) { 67 | return user; 68 | } 69 | 70 | @DELETE 71 | @Path("/{username}") 72 | public void delete(@PathParam("username") String username) { 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/example/security/ExampleAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import com.example.core.User; 4 | import com.google.common.base.Optional; 5 | import com.yammer.dropwizard.auth.AuthenticationException; 6 | import com.yammer.dropwizard.auth.Authenticator; 7 | 8 | /** 9 | * This is an example authenticator that takes the credentials extracted from the request by the SecurityProvider 10 | * and authenticates the principle 11 | */ 12 | public class ExampleAuthenticator implements Authenticator { 13 | 14 | @Override 15 | public Optional authenticate(ExampleCredentials credentials) throws AuthenticationException { 16 | 17 | // This is where you should call your authentication service and validate the token 18 | if (credentials.getToken().startsWith("fail")) { 19 | throw new AuthenticationException("Invalid credentials"); 20 | } else { 21 | User user = new User(); 22 | user.setDisplayName("User for token " + credentials.getToken()); 23 | user.setUsername(credentials.getToken()); 24 | user.setDisplayRole(credentials.getToken().contains("Admin") ? User.ROLE_ADMIN : User.ROLE_EDITOR); 25 | 26 | return Optional.fromNullable(user); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/example/security/ExampleCredentials.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * This class is an example of a POJO used to hold custom credentials to be used to link a request to a specific principle (User) 7 | */ 8 | public class ExampleCredentials { 9 | private final String token; 10 | 11 | public ExampleCredentials(String token) { 12 | this.token = token; 13 | } 14 | 15 | public String getToken() { 16 | return token; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/example/security/ExampleSecurityProvider.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import com.google.common.base.Optional; 4 | import com.sun.jersey.api.core.HttpContext; 5 | import com.sun.jersey.api.model.Parameter; 6 | import com.sun.jersey.core.spi.component.ComponentContext; 7 | import com.sun.jersey.core.spi.component.ComponentScope; 8 | import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable; 9 | import com.sun.jersey.spi.inject.Injectable; 10 | import com.sun.jersey.spi.inject.InjectableProvider; 11 | import com.yammer.dropwizard.auth.Auth; 12 | import com.yammer.dropwizard.auth.AuthenticationException; 13 | import com.yammer.dropwizard.auth.Authenticator; 14 | 15 | import javax.ws.rs.WebApplicationException; 16 | import javax.ws.rs.core.Response; 17 | 18 | /** 19 | * An example security provider that will look at each request when received by an endpoint using the auth attribute 20 | * and check that it has a header value containing a token and will authenticate the token to get the Principle (User) 21 | * for the request (otherwise throw an AuthenticationException). That Principle is the authenticated User associated 22 | * with the request and the resource method handling the request can use it to check authorisation to perform actions. 23 | * 24 | * @param The Principle class (User) to be returned when a request is authenticated 25 | */ 26 | public class ExampleSecurityProvider implements InjectableProvider { 27 | 28 | public final static String CUSTOM_HEADER = "custom-security-token"; 29 | 30 | private final Authenticator authenticator; 31 | 32 | public ExampleSecurityProvider(Authenticator authenticator) { 33 | this.authenticator = authenticator; 34 | } 35 | 36 | private static class ExampleSecurityInjectable extends AbstractHttpContextInjectable { 37 | 38 | private final Authenticator authenticator; 39 | private final boolean required; 40 | 41 | private ExampleSecurityInjectable(Authenticator authenticator, boolean required) { 42 | this.authenticator = authenticator; 43 | this.required = required; 44 | } 45 | 46 | @Override 47 | public T getValue(HttpContext c) { 48 | // This is where the credentials are extracted from the request 49 | final String header = c.getRequest().getHeaderValue(CUSTOM_HEADER); 50 | try { 51 | if (header != null) { 52 | final Optional result = authenticator.authenticate(new ExampleCredentials(header)); 53 | if (result.isPresent()) { 54 | return result.get(); 55 | } 56 | } 57 | } catch (AuthenticationException e) { 58 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 59 | } 60 | 61 | if (required) { 62 | throw new WebApplicationException(Response.Status.UNAUTHORIZED); 63 | } 64 | 65 | return null; 66 | } 67 | } 68 | 69 | @Override 70 | public ComponentScope getScope() { 71 | return ComponentScope.PerRequest; 72 | } 73 | 74 | @Override 75 | public Injectable getInjectable(ComponentContext ic, Auth auth, Parameter parameter) { 76 | return new ExampleSecurityInjectable(authenticator, auth.required()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/com/example/core/UserTests.java: -------------------------------------------------------------------------------- 1 | package com.example.core; 2 | 3 | import org.junit.BeforeClass; 4 | import org.junit.Test; 5 | 6 | import javax.validation.ConstraintViolation; 7 | import javax.validation.Validation; 8 | import javax.validation.Validator; 9 | import javax.validation.ValidatorFactory; 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | import static com.yammer.dropwizard.testing.JsonHelpers.asJson; 14 | import static com.yammer.dropwizard.testing.JsonHelpers.fromJson; 15 | import static com.yammer.dropwizard.testing.JsonHelpers.jsonFixture; 16 | import static org.junit.Assert.assertEquals; 17 | 18 | public class UserTests { 19 | 20 | private static final String NULL_ERROR_MESSAGE = "may not be null"; 21 | private static final String EMPTY_ERROR_MESSAGE = "may not be empty"; 22 | 23 | private static Validator validator; 24 | 25 | @BeforeClass 26 | public static void setUp() { 27 | ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 28 | validator = factory.getValidator(); 29 | } 30 | 31 | @Test 32 | public void serializesToJson() throws Exception { 33 | assertEquals(jsonFixture("fixtures/user.json"), asJson(getUser())); 34 | } 35 | 36 | @Test 37 | public void deserializesFromJSON() throws Exception { 38 | assertEquals(getUser(), fromJson(jsonFixture("fixtures/user.json"), User.class)); 39 | } 40 | 41 | // Should be replaced with individual class field validator tests 42 | @Test 43 | public void validate_not_null_or_empty() throws Exception { 44 | User user = new User(); 45 | 46 | Set> constraintViolations = 47 | validator.validate(user); 48 | 49 | assertEquals(4, constraintViolations.size()); 50 | assertEquals(EMPTY_ERROR_MESSAGE, constraintViolations.iterator().next().getMessage()); 51 | } 52 | 53 | public static User getUser() { 54 | User user = new User(); 55 | user.setUsername("myName"); 56 | user.setPassword("myPassword"); 57 | user.setDisplayName("myDisplayName"); 58 | user.setDisplayRole("myDisplayRole"); 59 | 60 | return user; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/example/resources/UserResourceTests.java: -------------------------------------------------------------------------------- 1 | package com.example.resources; 2 | 3 | import com.example.core.User; 4 | import com.example.core.UserTests; 5 | import com.example.security.ExampleAuthenticator; 6 | import com.example.security.ExampleSecurityProvider; 7 | import com.sun.jersey.api.client.GenericType; 8 | import com.sun.jersey.api.client.UniformInterfaceException; 9 | import com.yammer.dropwizard.testing.ResourceTest; 10 | import com.yammer.dropwizard.validation.InvalidEntityException; 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.junit.rules.ExpectedException; 14 | 15 | import javax.ws.rs.core.MediaType; 16 | import java.util.List; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.fail; 20 | 21 | public class UserResourceTests extends ResourceTest { 22 | 23 | @Rule 24 | public ExpectedException expectedException = ExpectedException.none(); 25 | 26 | @Override 27 | protected void setUpResources() { 28 | addResource(new UserResource()); 29 | 30 | // Need to add SecurityProvider to all resource tests for resources using Auth, or you get 415 response 31 | // you can inject the authenticator to mock authentication results while ensuring you test true to how 32 | // the call will be made 33 | final ExampleAuthenticator authenticator = new ExampleAuthenticator(); 34 | addProvider(new ExampleSecurityProvider<>(authenticator)); 35 | } 36 | 37 | @Test 38 | public void getAll() throws Exception { 39 | List users = client().resource("/user") 40 | .header(ExampleSecurityProvider.CUSTOM_HEADER, "validAdminToken") 41 | .get(new GenericType>() {}); 42 | assertEquals(2, users.size()); 43 | assertEquals("user1", users.get(0).getUsername()); 44 | } 45 | 46 | @Test 47 | public void getAllThrows401WhenNotAuthenticatedToken() throws Exception { 48 | try { 49 | client().resource("/user") 50 | .get(new GenericType>() {}); 51 | 52 | fail("Should have thrown 401"); 53 | } catch (UniformInterfaceException ex) { 54 | assertEquals(ex.getResponse().getStatus(), 401); 55 | } 56 | } 57 | 58 | @Test 59 | public void getAllThrows401WhenPrincipalNotDisplayRoleAdmin() throws Exception { 60 | try { 61 | client().resource("/user") 62 | .header(ExampleSecurityProvider.CUSTOM_HEADER, "validBasicToken") 63 | .get(new GenericType>() {}); 64 | 65 | fail("Should have thrown 401"); 66 | } catch (UniformInterfaceException ex) { 67 | assertEquals(ex.getResponse().getStatus(), 401); 68 | } 69 | } 70 | 71 | @Test 72 | public void get() throws Exception { 73 | User user = client().resource("/user/test1").get(User.class); 74 | assertEquals("test1", user.getUsername()); 75 | } 76 | 77 | @Test 78 | public void update() throws Exception { 79 | User user = UserTests.getUser(); 80 | 81 | User updatedUser = client().resource("/user/test1") 82 | .type(MediaType.APPLICATION_JSON) 83 | .put(User.class, user); 84 | 85 | assertEquals(user, updatedUser); 86 | } 87 | 88 | @Test 89 | public void update_invalid_user() throws Exception { 90 | expectedException.expect(InvalidEntityException.class); 91 | 92 | User user = UserTests.getUser().setDisplayName(""); 93 | 94 | User updatedUser = client().resource("/user/test1") 95 | .type(MediaType.APPLICATION_JSON) 96 | .put(User.class, user); 97 | } 98 | 99 | @Test() 100 | public void add() throws Exception { 101 | User newUser = UserTests.getUser(); 102 | 103 | User user = client().resource("/user") 104 | .type(MediaType.APPLICATION_JSON) 105 | .post(User.class, newUser); 106 | 107 | assertEquals(newUser, user); 108 | } 109 | 110 | @Test() 111 | public void add_invalid_user() throws Exception { 112 | expectedException.expect(InvalidEntityException.class); 113 | 114 | User newUser = UserTests.getUser().setUsername(null); 115 | 116 | User user = client().resource("/user") 117 | .type(MediaType.APPLICATION_JSON) 118 | .post(User.class, newUser); 119 | } 120 | 121 | @Test() 122 | public void delete() throws Exception { 123 | client().resource("/user/test1").delete(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/com/example/security/ExampleAuthenticatorTests.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import com.yammer.dropwizard.auth.AuthenticationException; 4 | import org.junit.Test; 5 | 6 | public class ExampleAuthenticatorTests { 7 | 8 | @Test 9 | public void authenticateReturnsUserForValidCredentials() throws AuthenticationException { 10 | ExampleAuthenticator exampleAuthenticator = new ExampleAuthenticator(); 11 | 12 | exampleAuthenticator.authenticate(new ExampleCredentials("validToken")); 13 | } 14 | 15 | @Test(expected = AuthenticationException.class) 16 | public void authenticateThrowsAuthenticationExceptionForInvalidCredentials() throws AuthenticationException { 17 | ExampleAuthenticator exampleAuthenticator = new ExampleAuthenticator(); 18 | 19 | exampleAuthenticator.authenticate(new ExampleCredentials("failToken")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/example/security/ExampleCredentialsTests.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.fail; 7 | 8 | public class ExampleCredentialsTests { 9 | 10 | @Test 11 | public void getToken() { 12 | ExampleCredentials credentials = new ExampleCredentials("1234"); 13 | assertEquals("1234", credentials.getToken()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/example/security/ExampleSecurityProviderTests.java: -------------------------------------------------------------------------------- 1 | package com.example.security; 2 | 3 | import com.example.core.User; 4 | import com.sun.jersey.api.client.UniformInterfaceException; 5 | import com.sun.jersey.test.framework.AppDescriptor; 6 | import com.sun.jersey.test.framework.JerseyTest; 7 | import com.sun.jersey.test.framework.LowLevelAppDescriptor; 8 | import com.yammer.dropwizard.auth.Auth; 9 | import com.yammer.dropwizard.config.LoggingFactory; 10 | import com.yammer.dropwizard.jersey.DropwizardResourceConfig; 11 | import org.junit.Test; 12 | 13 | import javax.ws.rs.GET; 14 | import javax.ws.rs.Path; 15 | import javax.ws.rs.Produces; 16 | import javax.ws.rs.core.MediaType; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.fail; 20 | 21 | /** 22 | * Tests for provider based on Dropwizard BasicAuthProviderTests 23 | * https://github.com/dropwizard/dropwizard/blob/master/dropwizard-auth/src/test/java/io/dropwizard/auth/basic/BasicAuthProviderTest.java 24 | * 25 | * This is where you test your provider acts as expected when injected and used by the auth attributes in a resource 26 | */ 27 | public class ExampleSecurityProviderTests extends JerseyTest { 28 | 29 | static { 30 | LoggingFactory.bootstrap(); 31 | } 32 | 33 | @Path("/test/") 34 | @Produces(MediaType.TEXT_PLAIN) 35 | public static class ExampleResource { 36 | @GET 37 | public String show(@Auth User principal) { 38 | return principal.getUsername(); 39 | } 40 | } 41 | 42 | @Override 43 | protected AppDescriptor configure() { 44 | final DropwizardResourceConfig config = new DropwizardResourceConfig(true); 45 | final ExampleAuthenticator authenticator = new ExampleAuthenticator(); 46 | 47 | config.getSingletons().add(new ExampleSecurityProvider<>(authenticator)); 48 | config.getSingletons().add(new ExampleResource()); 49 | 50 | return new LowLevelAppDescriptor.Builder(config).build(); 51 | } 52 | 53 | @Test 54 | public void respondsToMissingCredentialsWith401() throws Exception { 55 | try { 56 | client().resource("/test") 57 | .get(String.class); 58 | 59 | fail("Should have thrown 401"); 60 | } catch (UniformInterfaceException ex) { 61 | assertEquals(ex.getResponse().getStatus(), 401); 62 | } 63 | } 64 | 65 | @Test 66 | public void transformsCredentialsToPrincipals() throws Exception { 67 | assertEquals(client().resource("/test") 68 | .header(ExampleSecurityProvider.CUSTOM_HEADER, "validTokenReturnedAsUsername") 69 | .get(String.class), 70 | "validTokenReturnedAsUsername"); 71 | } 72 | 73 | @Test 74 | public void respondsToNonBasicCredentialsWith401() throws Exception { 75 | try { 76 | client().resource("/test") 77 | .header(ExampleSecurityProvider.CUSTOM_HEADER, "failToken") 78 | .get(String.class); 79 | 80 | fail("Should have thrown 401"); 81 | } catch (UniformInterfaceException ex) { 82 | assertEquals(ex.getResponse().getStatus(), 401); 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/resources/fixtures/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": "myName", 3 | "password": "myPassword", 4 | "displayName": "myDisplayName", 5 | "displayRole": "myDisplayRole" 6 | } --------------------------------------------------------------------------------