diff --git a/lab-06-answer/LAB.md b/lab-06-answer/LAB.md new file mode 100644 index 0000000..121362d --- /dev/null +++ b/lab-06-answer/LAB.md @@ -0,0 +1,17 @@ +# Lab 06 - Security + +What good is a web app without any security? + +Ratpack has a great Pac4j module, we can use this to easily secure a few endpoints. + +## This lab covers + +* Basic Pac4j Setup +* Basic Auth +* Using user details of the logged in user + +## Sign Posts + +* SessionModule +* [ratpack.pac4j.RatpackPac4j](http://ratpack.io/manual/current/api/index.html?ratpack/pac4j/RatpackPac4j.html) +* [BasicAuthClient](http://static.javadoc.io/org.pac4j/pac4j-http/1.7.1/index.html?org/pac4j/http/client/BasicAuthClient.html) diff --git a/lab-06-answer/lab-06-answer.gradle b/lab-06-answer/lab-06-answer.gradle new file mode 100644 index 0000000..2642e4a --- /dev/null +++ b/lab-06-answer/lab-06-answer.gradle @@ -0,0 +1,8 @@ +dependencies { + compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.3' + compile ratpack.dependency('guice') + compile ratpack.dependency('session') + + compile ratpack.dependency('pac4j') + compile "org.pac4j:pac4j-http:1.7.0" +} diff --git a/lab-06-answer/src/main/java/lab06/Lab06.java b/lab-06-answer/src/main/java/lab06/Lab06.java new file mode 100644 index 0000000..61b57d4 --- /dev/null +++ b/lab-06-answer/src/main/java/lab06/Lab06.java @@ -0,0 +1,40 @@ +package lab06; + +import org.pac4j.http.client.BasicAuthClient; +import org.pac4j.http.credentials.SimpleTestUsernamePasswordAuthenticator; +import org.pac4j.http.profile.HttpProfile; +import org.pac4j.http.profile.UsernameProfileCreator; +import ratpack.guice.Guice; +import ratpack.handling.Context; +import ratpack.handling.InjectionHandler; +import ratpack.pac4j.RatpackPac4j; +import ratpack.server.BaseDir; +import ratpack.server.RatpackServer; +import ratpack.session.SessionModule; + +public class Lab06 { + + public static void main(String[] args) throws Exception { + RatpackServer.start(ratpackServerSpec -> { + ratpackServerSpec + .serverConfig(s -> s.baseDir(BaseDir.find())) + .registry(Guice.registry(bindingsSpec -> { + bindingsSpec.module(SessionModule.class); + })) + .handlers(chain -> { + chain + .all(RatpackPac4j.authenticator(new BasicAuthClient(new SimpleTestUsernamePasswordAuthenticator(), new UsernameProfileCreator()))) + .get(ctx -> ctx.render("Root GET")) + .all(RatpackPac4j.requireAuth(BasicAuthClient.class)) + .get("secure", new InjectionHandler() { + void handle(Context ctx, HttpProfile profile) { + ctx.render("Secure stuff for " + profile.getUsername() + "!"); + } + }); + }); + } + + ); + } + +} diff --git a/lab-06-answer/src/ratpack/.ratpack b/lab-06-answer/src/ratpack/.ratpack new file mode 100644 index 0000000..e69de29 diff --git a/lab-06-answer/src/test/groovy/SecuritySpec.groovy b/lab-06-answer/src/test/groovy/SecuritySpec.groovy new file mode 100644 index 0000000..68f5720 --- /dev/null +++ b/lab-06-answer/src/test/groovy/SecuritySpec.groovy @@ -0,0 +1,77 @@ +import lab06.Lab06 +import ratpack.test.ApplicationUnderTest +import ratpack.test.MainClassApplicationUnderTest +import ratpack.test.http.TestHttpClient +import spock.lang.Shared +import spock.lang.Specification + +class SecuritySpec extends Specification { + + @Shared + ApplicationUnderTest aut = new MainClassApplicationUnderTest(Lab06) + + @Delegate + TestHttpClient testHttpClient = aut.httpClient + + def cleanup() { + resetRequest() + } + + def "01 - Can get root"() { + expect: + getText() == "Root GET" + } + + def "02 - Can not get secured content"() { + when: + def resp = get("secure") + + then: + resp.statusCode == 401 + + /* + Hint: + ratpack.pac4j.RatpackPac4j has some static methods that make wiring up security easy. + */ + } + + def "03 - Can get secured content with basic auth"() { + given: + def user = "TestUser" + + and: + requestSpec({ requestSpec -> + requestSpec.basicAuth(user, user) + }) + + when: + def resp = get("secure") + + then: + resp.statusCode == 200 + resp.body.getText().contains("Secure stuff") + } + + def "04 - Can display the username of the authenticated user"() { + given: + def user = "Usser" + UUID.randomUUID() + + and: + requestSpec({ requestSpec -> + requestSpec.basicAuth(user, user) + }) + + when: + def resp = get("secure") + + then: + resp.statusCode == 200 + resp.body.getText().contains(user) + + /* + Hint: UsernameProfileCreator will create a HttpProfile and it should be in the registry. + */ + + } + +} diff --git a/lab-06/LAB.md b/lab-06/LAB.md new file mode 100644 index 0000000..121362d --- /dev/null +++ b/lab-06/LAB.md @@ -0,0 +1,17 @@ +# Lab 06 - Security + +What good is a web app without any security? + +Ratpack has a great Pac4j module, we can use this to easily secure a few endpoints. + +## This lab covers + +* Basic Pac4j Setup +* Basic Auth +* Using user details of the logged in user + +## Sign Posts + +* SessionModule +* [ratpack.pac4j.RatpackPac4j](http://ratpack.io/manual/current/api/index.html?ratpack/pac4j/RatpackPac4j.html) +* [BasicAuthClient](http://static.javadoc.io/org.pac4j/pac4j-http/1.7.1/index.html?org/pac4j/http/client/BasicAuthClient.html) diff --git a/lab-06/lab-06.gradle b/lab-06/lab-06.gradle new file mode 100644 index 0000000..2642e4a --- /dev/null +++ b/lab-06/lab-06.gradle @@ -0,0 +1,8 @@ +dependencies { + compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.3' + compile ratpack.dependency('guice') + compile ratpack.dependency('session') + + compile ratpack.dependency('pac4j') + compile "org.pac4j:pac4j-http:1.7.0" +} diff --git a/lab-06/src/main/java/lab06/Lab06.java b/lab-06/src/main/java/lab06/Lab06.java new file mode 100644 index 0000000..adabc72 --- /dev/null +++ b/lab-06/src/main/java/lab06/Lab06.java @@ -0,0 +1,24 @@ +package lab06; + +import ratpack.guice.Guice; +import ratpack.server.BaseDir; +import ratpack.server.RatpackServer; + +public class Lab06 { + + public static void main(String[] args) throws Exception { + RatpackServer.start(ratpackServerSpec -> { + ratpackServerSpec + .serverConfig(s -> s.baseDir(BaseDir.find())) + .registry(Guice.registry(bindingsSpec -> { + //Add any needed modules + })) + .handlers(chain -> { + //Add handlers + }); + } + + ); + } + +} diff --git a/lab-06/src/ratpack/.ratpack b/lab-06/src/ratpack/.ratpack new file mode 100644 index 0000000..e69de29 diff --git a/lab-06/src/test/groovy/SecuritySpec.groovy b/lab-06/src/test/groovy/SecuritySpec.groovy new file mode 100644 index 0000000..68f5720 --- /dev/null +++ b/lab-06/src/test/groovy/SecuritySpec.groovy @@ -0,0 +1,77 @@ +import lab06.Lab06 +import ratpack.test.ApplicationUnderTest +import ratpack.test.MainClassApplicationUnderTest +import ratpack.test.http.TestHttpClient +import spock.lang.Shared +import spock.lang.Specification + +class SecuritySpec extends Specification { + + @Shared + ApplicationUnderTest aut = new MainClassApplicationUnderTest(Lab06) + + @Delegate + TestHttpClient testHttpClient = aut.httpClient + + def cleanup() { + resetRequest() + } + + def "01 - Can get root"() { + expect: + getText() == "Root GET" + } + + def "02 - Can not get secured content"() { + when: + def resp = get("secure") + + then: + resp.statusCode == 401 + + /* + Hint: + ratpack.pac4j.RatpackPac4j has some static methods that make wiring up security easy. + */ + } + + def "03 - Can get secured content with basic auth"() { + given: + def user = "TestUser" + + and: + requestSpec({ requestSpec -> + requestSpec.basicAuth(user, user) + }) + + when: + def resp = get("secure") + + then: + resp.statusCode == 200 + resp.body.getText().contains("Secure stuff") + } + + def "04 - Can display the username of the authenticated user"() { + given: + def user = "Usser" + UUID.randomUUID() + + and: + requestSpec({ requestSpec -> + requestSpec.basicAuth(user, user) + }) + + when: + def resp = get("secure") + + then: + resp.statusCode == 200 + resp.body.getText().contains(user) + + /* + Hint: UsernameProfileCreator will create a HttpProfile and it should be in the registry. + */ + + } + +} diff --git a/settings.gradle b/settings.gradle index 5fdee9f..b500ad7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,9 @@ include \ 'lab-04', 'lab-04-answer', 'lab-05', - 'lab-05-answer' + 'lab-05-answer', + 'lab-06', + 'lab-06-answer' rootProject.name = 'hands-on-ratpack'