├── .travis.yml
├── src
├── main
│ ├── resources
│ │ ├── samlKeystore.jks
│ │ ├── logback.xml
│ │ ├── metadata-okta.xml
│ │ └── testshib-providers.xml
│ ├── templates
│ │ ├── error403.html
│ │ ├── error404.html
│ │ ├── jwt.html
│ │ ├── error401.html
│ │ ├── error500.html
│ │ ├── protectedIndex.html
│ │ ├── loginForm.html
│ │ └── index.html
│ └── java
│ │ └── org
│ │ └── pac4j
│ │ └── demo
│ │ └── ratpack
│ │ ├── Template.java
│ │ ├── TemplateRenderer.java
│ │ └── RatpackPac4jDemo.java
└── test
│ └── java
│ └── org
│ └── pac4j
│ └── demo
│ └── ratpack
│ └── RatpackTest.java
├── .gitignore
├── renovate.json
├── .editorconfig
├── README.md
├── .github
└── workflows
│ └── build-and-test.yml
├── pom.xml
└── ci
└── run_and_check.sh
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | sudo: false
4 |
5 | jdk:
6 | - oraclejdk8
7 |
--------------------------------------------------------------------------------
/src/main/resources/samlKeystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pac4j/ratpack-pac4j-demo/HEAD/src/main/resources/samlKeystore.jks
--------------------------------------------------------------------------------
/src/main/templates/error403.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | forbidden
4 |
5 | Home
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/templates/error404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | not found
4 |
5 | Home
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/templates/jwt.html:
--------------------------------------------------------------------------------
1 | Generate JWT token
2 | Back
3 |
4 | token: ${model.token}
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 | .settings/
4 | target/
5 | test-output/
6 | bin/
7 | .idea
8 | *.iml
9 | sp-metadata*.xml
10 |
--------------------------------------------------------------------------------
/src/main/templates/error401.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | unauthorized
4 |
5 | Home
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/templates/error500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | internal error
4 |
5 | Home
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/templates/protectedIndex.html:
--------------------------------------------------------------------------------
1 | protected area
2 | Back
3 |
4 | profile : ${model.profile}
5 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "local>pac4j/renovate-config"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/org/pac4j/demo/ratpack/Template.java:
--------------------------------------------------------------------------------
1 | package org.pac4j.demo.ratpack;
2 |
3 | import java.util.Map;
4 |
5 | public record Template(String id, Map model) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/templates/loginForm.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RATPACK PAC4J DEMO %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | # Change these settings to your own preference
9 | indent_style = space
10 | indent_size = 4
11 |
12 | # We recommend you to keep these unchanged
13 | end_of_line = lf
14 | charset = utf-8
15 | trim_trailing_whitespace = true
16 | insert_final_newline = true
17 |
18 | [*.md]
19 | trim_trailing_whitespace = false
20 | indent_style = space
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This `ratpack-pac4j-demo` project is a Ratpack web application to test the [ratpack-pac4j](https://github.com/ratpack/ratpack/tree/master/ratpack-pac4j) security module with various authentication mechanisms: Facebook, Twitter, form, basic auth, CAS, SAML, OpenID Connect, JWT...
6 |
7 | ## Start & test
8 |
9 | Build the project and launch the web app on [http://localhost:8080](http://localhost:8080):
10 |
11 | cd ratpack-pac4j-demo
12 | mvn clean compile exec:java
13 |
14 | To test, you can call a protected url by clicking on the "Protected url by **xxx**" link, which will start the authentication process with the **xxx** provider.
15 |
16 | ## Automatic build [](https://travis-ci.org/pac4j/ratpack-pac4j-demo)
17 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-test.yml:
--------------------------------------------------------------------------------
1 | name: Build and Test
2 |
3 | on:
4 | push:
5 | branches: [ main, master ]
6 | pull_request:
7 | branches: [ main, master ]
8 |
9 | jobs:
10 | build-and-test:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
16 |
17 | - name: Set up JDK 17
18 | uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5
19 | with:
20 | java-version: '17'
21 | distribution: 'temurin'
22 |
23 | - name: Cache Maven dependencies
24 | uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5
25 | with:
26 | path: ~/.m2
27 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
28 | restore-keys: ${{ runner.os }}-m2
29 |
30 | - name: Run build and test
31 | run: |
32 | cd ci
33 | chmod +x run_and_check.sh
34 | ./run_and_check.sh
35 |
36 | - name: Upload test logs
37 | if: failure()
38 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
39 | with:
40 | name: server-logs
41 | path: target/server.log
42 |
--------------------------------------------------------------------------------
/src/main/java/org/pac4j/demo/ratpack/TemplateRenderer.java:
--------------------------------------------------------------------------------
1 | package org.pac4j.demo.ratpack;
2 |
3 | import com.google.inject.Inject;
4 | import java.nio.file.Files;
5 | import java.util.Optional;
6 | import java.util.regex.Pattern;
7 | import ratpack.file.FileSystemBinding;
8 | import ratpack.handling.Context;
9 | import ratpack.render.Renderer;
10 |
11 | public class TemplateRenderer implements Renderer {
12 |
13 | private static Pattern REGEX = Pattern.compile("\\$\\{model.(\\w+)}");
14 |
15 | private final FileSystemBinding fileSystemBinding;
16 |
17 | @Inject
18 | TemplateRenderer(FileSystemBinding fileSystemBinding) {
19 | this.fileSystemBinding = fileSystemBinding;
20 | }
21 |
22 | @Override
23 | public Class getType() {
24 | return Template.class;
25 | }
26 |
27 | @Override
28 | public void render(Context context, Template template) throws Exception {
29 | var file = context.get(FileSystemBinding.class).file("templates/" + template.id());
30 | var text = Files.readString(file);
31 | var templated = REGEX.matcher(text)
32 | .replaceAll(m -> Optional.ofNullable(template.model().get(m.group(1))).map(Object::toString).orElse("null"));
33 | context.getResponse().contentType("text/html");
34 | context.getResponse().send(templated);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/templates/index.html:
--------------------------------------------------------------------------------
1 | index
2 | Protected url by Facebook: facebook/index.html (use a real account)
3 | Protected url by Facebook with ROLE_ADMIN: facebookadmin/index.html (use a real account)
4 | Protected url by Facebook with custom authorizer (= must be a profile whose id starts with with "jle"): facebookcustom/index.html (login with form or basic authentication before with jle* username)
5 | Protected url by Twitter: twitter/index.html (use a real account)
6 | Protected url by form authentication: form/index.html (use login = pwd)
7 | Protected url by basic auth: basicauth/index.html (use login = pwd)
8 | Protected url by CAS: cas/index.html (use jleleu/jleleu)
9 | Protected url by SAML: saml2/index.html (use testpac4j@gmail.com/Pac4jtest)
10 | Protected url by Google OpenID Connect: oidc/index.html (use a real account)
11 |
12 | Generate a JWT token (after being authenticated)
13 | Protected url by DirectBasicAuthClient: /dba/index.jsp (POST the Authorization header with value: Basic amxlbGV1OmpsZWxldQ==)
14 | Protected url by ParameterClient: /rest-jwt/index.jsp (with request parameter: token=jwt_generated_token)
15 |
16 | logout
17 |
18 | profile : ${model.profile}
19 |
--------------------------------------------------------------------------------
/src/test/java/org/pac4j/demo/ratpack/RatpackTest.java:
--------------------------------------------------------------------------------
1 | package org.pac4j.demo.ratpack;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertThat;
5 | import static org.junit.matchers.JUnitMatchers.containsString;
6 |
7 | import io.netty.handler.codec.http.HttpHeaderNames;
8 | import org.junit.After;
9 | import org.junit.Test;
10 | import ratpack.http.client.ReceivedResponse;
11 | import ratpack.test.CloseableApplicationUnderTest;
12 | import ratpack.test.MainClassApplicationUnderTest;
13 | import ratpack.test.http.TestHttpClient;
14 |
15 | public class RatpackTest {
16 |
17 | private final CloseableApplicationUnderTest aut = new MainClassApplicationUnderTest(RatpackPac4jDemo.class);
18 | private final TestHttpClient httpClient = aut.getHttpClient();
19 |
20 | @After
21 | public void tearDown() throws Exception {
22 | aut.close();
23 | }
24 |
25 | @Test
26 | public void redirectsToIndexHtml() {
27 | final ReceivedResponse response = httpClient.get();
28 | assertEquals(200, response.getStatusCode());
29 | assertThat(response.getBody().getText(), containsString("index
"));
30 | }
31 |
32 | @Test
33 | public void requiresFormAuth() {
34 | ReceivedResponse response = httpClient.get("form/index.html");
35 | assertEquals(200, response.getStatusCode());
36 | assertThat(response.getBody().getText(), containsString("