Skip to content

Commit fe06e75

Browse files
Merge pull request #4884 from pedroigor/issue-4480
[fixes #4480] - Initial Code Flow Support
2 parents f6d0aaf + 4b2c71b commit fe06e75

File tree

37 files changed

+1336
-221
lines changed

37 files changed

+1336
-221
lines changed

azure-pipelines.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,11 @@ stages:
233233

234234
- template: ci-templates/native-build-steps.yaml
235235
parameters:
236-
timeoutInMinutes: 20
236+
timeoutInMinutes: 25
237237
modules:
238238
- elytron-resteasy
239239
- oidc
240+
- oidc-code-flow
240241
- vault-app
241242
- keycloak-authorization
242243
name: security_2

docs/src/main/asciidoc/index.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ include::quarkus-intro.adoc[tag=intro]
4545
* link:writing-native-applications-tips.html[Tips for writing native applications] _(advanced)_
4646
* link:performance-measure.html[Measuring Performance] _(advanced)_
4747
* link:cdi-reference.html[Contexts and Dependency Injection] _(advanced)_
48-
* link:oidc-guide.html[Using OpenID Connect Adapter]
48+
* link:oidc-guide.html[Using OpenID Connect Adapter to Protect JAX-RS Applications]
49+
* link:oidc-web-app-guide.html[Protecting Web Applications Using OpenID Connect]
4950
* link:keycloak-authorization-guide.html[Keycloak Authorization]
5051
* link:kogito-guide.html[Using Kogito (business automation with processes and rules)]
5152
* link:oauth2-guide.html[Using OAuth2 RBAC]
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
////
2+
This guide is maintained in the main Quarkus repository
3+
and pull requests should be submitted there:
4+
https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
5+
////
6+
= Quarkus - Protecting Web Applications Using OpenID Connect
7+
8+
include::./attributes.adoc[]
9+
10+
This guide demonstrates how to use the OpenID Connect Extension to protect your application using Quarkus, where authentication and authorization are based on tokens issued by OpenId Connect and OAuth 2.0 compliant Authorization Servers such as https://www.keycloak.org/about.html[Keycloak].
11+
12+
The extension allows you to easily enable authentication to your web application based on the Authorization Code Flow so that your users are redirected to a
13+
OpenID Connect Provider (e.g.: Keycloak) to authenticate and, once the authentication is complete, return back to your application.
14+
15+
We are going to give you a guideline on how to use OpenId Connect to authenticate users using the Quarkus OpenID Connect Extenson.
16+
17+
== Prerequisites
18+
19+
To complete this guide, you need:
20+
21+
* less than 15 minutes
22+
* an IDE
23+
* JDK 1.8+ installed with `JAVA_HOME` configured appropriately
24+
* Apache Maven 3.5.3+
25+
* https://stedolan.github.io/jq/[jq tool]
26+
* Docker
27+
28+
== Architecture
29+
30+
In this example, we build a very simple web application with a single page:
31+
32+
* `/index.html`
33+
34+
This page is protected and can only be accessed by authenticated users.
35+
36+
== Solution
37+
38+
We recommend that you follow the instructions in the next sections and create the application step by step.
39+
However, you can go right to the completed example.
40+
41+
Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive].
42+
43+
The solution is located in the `openid-connect-web-authentication` {quickstarts-tree-url}/openid-connect-web-authentication[directory].
44+
45+
== Creating the Maven Project
46+
47+
First, we need a new project. Create a new project with the following command:
48+
49+
[source, subs=attributes+]
50+
----
51+
mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \
52+
-DprojectGroupId=org.acme \
53+
-DprojectArtifactId=openid-connect-web-authentication \
54+
-Dextensions="oidc"
55+
----
56+
57+
== Configuring the application
58+
59+
The OpenID Connect extension allows you to define the configuration using the `application.properties` file which should be located at the `src/main/resources` directory.
60+
61+
=== Configuring using the application.properties file
62+
63+
[source,properties]
64+
----
65+
quarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/quarkus
66+
quarkus.oidc.client-id=frontend
67+
quarkus.oidc.client-type=web-app
68+
69+
----
70+
71+
Note that the `quarkus.oidc.client-type` is set to `web-app`. This setting tells Quarkus that you want to enable the OpenID Connect Authorization Code Flow, so that your users are redirected to the OpenID Connect Provider to authenticate.
72+
73+
== Starting and Configuring the Keycloak Server
74+
75+
To start a Keycloak Server you can use Docker and just run the following command:
76+
77+
[source,bash]
78+
----
79+
docker run --name keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak
80+
----
81+
82+
You should be able to access your Keycloak Server at http://localhost:8180/auth[localhost:8180/auth].
83+
84+
Log in as the `admin` user to access the Keycloak Administration Console. Username should be `admin` and password `admin`.
85+
86+
Import the {quickstarts-tree-url}/openid-connect-web-authentication/config/quarkus-realm.json[realm configuration file] to create a new realm. For more details, see the Keycloak documentation about how to https://www.keycloak.org/docs/latest/server_admin/index.html#_create-realm[create a new realm].
87+
88+
== Running and Using the Application
89+
90+
=== Running in Developer Mode
91+
92+
To run the microservice in dev mode, use `./mvnw clean compile quarkus:dev`.
93+
94+
=== Running in JVM Mode
95+
96+
When you're done playing with "dev-mode" you can run it as a standard Java application.
97+
98+
First compile it:
99+
100+
[source,bash]
101+
----
102+
./mvnw package
103+
----
104+
105+
Then run it:
106+
107+
[source,bash]
108+
----
109+
java -jar ./target/openid-connect-runner.jar
110+
----
111+
112+
=== Running in Native Mode
113+
114+
This same demo can be compiled into native code: no modifications required.
115+
116+
This implies that you no longer need to install a JVM on your
117+
production environment, as the runtime technology is included in
118+
the produced binary, and optimized to run with minimal resource overhead.
119+
120+
Compilation will take a bit longer, so this step is disabled by default;
121+
let's build again by enabling the `native` profile:
122+
123+
[source,bash]
124+
----
125+
./mvnw package -Pnative
126+
----
127+
128+
After getting a cup of coffee, you'll be able to run this binary directly:
129+
130+
[source,bash]
131+
----
132+
./target/openid-connect-web-authentication-runner
133+
----
134+
135+
== Testing the Application
136+
137+
To test the application, you should open your browser and access the following URL:
138+
139+
* http://localhost:8080[http://localhost:8080]
140+
141+
If everything is working as expected, you should be redirected to the Keycloak server to authenticate.
142+
143+
In order to authenticate to the application you should type the following credentials when at the Keycloak login page:
144+
145+
* Username: *alice*
146+
* Password: *alice*
147+
148+
After clicking the `Login` button you should be redirected back to the application.
149+
150+
== Logout
151+
152+
The extension only supports logout based on the expiration time of the ID Token issued by the OpenID Connect Provider. When the token expires, users are redirected to the OpenID Connect Provider again to authenticate. If the session at the OpenID Connect Provider is still active, users are automatically re-authenticated without having to provide their credentials again.
153+
154+
== Configuration Reference
155+
156+
include::{generated-dir}/config/quarkus-oidc.adoc[opts=optional]
157+
158+
== References
159+
160+
* https://www.keycloak.org/documentation.html[Keycloak Documentation]
161+
* https://openid.net/connect/[OpenID Connect]
162+
* https://tools.ietf.org/html/rfc7519[JSON Web Token]

extensions/keycloak-authorization/deployment/src/main/java/io/quarkus/keycloak/pep/KeycloakPolicyEnforcerBuildStep.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io.quarkus.deployment.annotations.ExecutionTime;
77
import io.quarkus.deployment.annotations.Record;
88
import io.quarkus.deployment.builditem.EnableAllSecurityServicesBuildItem;
9-
import io.quarkus.oidc.OidcConfig;
9+
import io.quarkus.oidc.runtime.OidcConfig;
1010

1111
public class KeycloakPolicyEnforcerBuildStep {
1212

extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/KeycloakPolicyEnforcerAuthorizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
2020

2121
import io.quarkus.arc.AlternativePriority;
22-
import io.quarkus.oidc.OidcConfig;
22+
import io.quarkus.oidc.runtime.OidcConfig;
2323
import io.quarkus.security.identity.SecurityIdentity;
2424
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
2525
import io.quarkus.vertx.http.runtime.security.HttpAuthorizer;

extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/KeycloakPolicyEnforcerRecorder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.quarkus.keycloak.pep;
22

33
import io.quarkus.arc.runtime.BeanContainer;
4-
import io.quarkus.oidc.OidcConfig;
4+
import io.quarkus.oidc.runtime.OidcConfig;
55
import io.quarkus.runtime.annotations.Recorder;
66

77
@Recorder
Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.quarkus.vertx.keycloak.deployment;
1+
package io.quarkus.oidc.deployment;
22

33
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
44
import io.quarkus.arc.deployment.BeanContainerBuildItem;
@@ -7,14 +7,15 @@
77
import io.quarkus.deployment.annotations.Record;
88
import io.quarkus.deployment.builditem.EnableAllSecurityServicesBuildItem;
99
import io.quarkus.deployment.builditem.FeatureBuildItem;
10-
import io.quarkus.oidc.OidcConfig;
11-
import io.quarkus.oidc.VertxJwtPrincipalProducer;
12-
import io.quarkus.oidc.VertxKeycloakRecorder;
13-
import io.quarkus.oidc.VertxOAuth2AuthenticationMechanism;
14-
import io.quarkus.oidc.VertxOAuth2IdentityProvider;
10+
import io.quarkus.oidc.runtime.BearerAuthenticationMechanism;
11+
import io.quarkus.oidc.runtime.CodeAuthenticationMechanism;
12+
import io.quarkus.oidc.runtime.OidcConfig;
13+
import io.quarkus.oidc.runtime.OidcIdentityProvider;
14+
import io.quarkus.oidc.runtime.OidcJsonWebTokenProducer;
15+
import io.quarkus.oidc.runtime.OidcRecorder;
1516
import io.quarkus.vertx.deployment.VertxBuildItem;
1617

17-
public class VertxKeycloakBuildStep {
18+
public class OidcBuildStep {
1819

1920
@BuildStep
2021
FeatureBuildItem featureBuildItem() {
@@ -24,10 +25,15 @@ FeatureBuildItem featureBuildItem() {
2425
@BuildStep
2526
public AdditionalBeanBuildItem beans(OidcConfig config) {
2627
if (config.enabled) {
27-
return AdditionalBeanBuildItem.builder().setUnremovable()
28-
.addBeanClass(VertxOAuth2AuthenticationMechanism.class)
29-
.addBeanClass(VertxJwtPrincipalProducer.class)
30-
.addBeanClass(VertxOAuth2IdentityProvider.class).build();
28+
AdditionalBeanBuildItem.Builder beans = AdditionalBeanBuildItem.builder().setUnremovable();
29+
30+
if (OidcConfig.ApplicationType.SERVICE.equals(config.getApplicationType())) {
31+
beans.addBeanClass(BearerAuthenticationMechanism.class);
32+
} else if (OidcConfig.ApplicationType.WEB_APP.equals(config.getApplicationType())) {
33+
beans.addBeanClass(CodeAuthenticationMechanism.class);
34+
}
35+
36+
return beans.addBeanClass(OidcJsonWebTokenProducer.class).addBeanClass(OidcIdentityProvider.class).build();
3137
}
3238

3339
return null;
@@ -40,7 +46,7 @@ EnableAllSecurityServicesBuildItem security() {
4046

4147
@Record(ExecutionTime.RUNTIME_INIT)
4248
@BuildStep
43-
public void setup(OidcConfig config, VertxKeycloakRecorder recorder, VertxBuildItem vertxBuildItem,
49+
public void setup(OidcConfig config, OidcRecorder recorder, VertxBuildItem vertxBuildItem,
4450
BeanContainerBuildItem bc) {
4551
if (config.enabled) {
4652
recorder.setup(config, vertxBuildItem.getVertx(), bc.getValue());
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.quarkus.oidc;
2+
3+
import static java.lang.annotation.ElementType.CONSTRUCTOR;
4+
import static java.lang.annotation.ElementType.FIELD;
5+
import static java.lang.annotation.ElementType.METHOD;
6+
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.lang.annotation.Target;
10+
11+
import javax.inject.Qualifier;
12+
13+
@Qualifier
14+
@Target({ FIELD, CONSTRUCTOR, METHOD })
15+
@Retention(RetentionPolicy.RUNTIME)
16+
public @interface IdToken {
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.quarkus.oidc;
2+
3+
import io.quarkus.security.credential.TokenCredential;
4+
5+
/**
6+
* Represents a refresh token issued to the application.
7+
*/
8+
public class RefreshToken extends TokenCredential {
9+
10+
public RefreshToken() {
11+
this(null);
12+
}
13+
14+
public RefreshToken(String token) {
15+
super(token, "refresh_token");
16+
}
17+
18+
// TODO: more methods to help the application to refresh tokens
19+
}

extensions/oidc/runtime/src/main/java/io/quarkus/oidc/VertxJwtPrincipalProducer.java

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)