-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add documentation for Jetty OpenID Connect support #12559
base: jetty-12.0.x
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// | ||
// ======================================================================== | ||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
// which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
// ======================================================================== | ||
// | ||
|
||
package org.eclipse.jetty.docs.programming.security; | ||
|
||
import java.util.Map; | ||
|
||
import org.eclipse.jetty.client.HttpClient; | ||
import org.eclipse.jetty.security.Authenticator; | ||
import org.eclipse.jetty.security.HashLoginService; | ||
import org.eclipse.jetty.security.LoginService; | ||
import org.eclipse.jetty.security.SecurityHandler; | ||
import org.eclipse.jetty.security.UserStore; | ||
import org.eclipse.jetty.security.openid.OpenIdAuthenticator; | ||
import org.eclipse.jetty.security.openid.OpenIdConfiguration; | ||
import org.eclipse.jetty.security.openid.OpenIdLoginService; | ||
import org.eclipse.jetty.server.Request; | ||
import org.eclipse.jetty.util.security.Credential; | ||
|
||
public class OpenIdDocs | ||
{ | ||
private static final String ISSUER = ""; | ||
private static final String CLIENT_ID = ""; | ||
private static final String CLIENT_SECRET = ""; | ||
private static final String TOKEN_ENDPOINT = ""; | ||
private static final String AUTH_ENDPOINT = ""; | ||
private static final String END_SESSION_ENDPOINT = ""; | ||
private static final String AUTH_METHOD = ""; | ||
private static final HttpClient httpClient = new HttpClient(); | ||
|
||
private OpenIdConfiguration openIdConfig; | ||
private SecurityHandler securityHandler; | ||
|
||
public void createConfigurationWithDiscovery() | ||
{ | ||
// tag::createConfigurationWithDiscovery[] | ||
OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, CLIENT_ID, CLIENT_SECRET); | ||
// end::createConfigurationWithDiscovery[] | ||
} | ||
|
||
public void createConfiguration() | ||
{ | ||
// tag::createConfiguration[] | ||
OpenIdConfiguration openIdConfig = new OpenIdConfiguration(ISSUER, TOKEN_ENDPOINT, AUTH_ENDPOINT, END_SESSION_ENDPOINT, | ||
CLIENT_ID, CLIENT_SECRET, AUTH_METHOD, httpClient); | ||
// end::createConfiguration[] | ||
} | ||
|
||
public void configureLoginService() | ||
{ | ||
// tag::configureLoginService[] | ||
LoginService loginService = new OpenIdLoginService(openIdConfig); | ||
securityHandler.setLoginService(loginService); | ||
// end::configureLoginService[] | ||
} | ||
|
||
public void configureAuthenticator() | ||
{ | ||
// tag::configureAuthenticator[] | ||
Authenticator authenticator = new OpenIdAuthenticator(openIdConfig, "/error"); | ||
securityHandler.setAuthenticator(authenticator); | ||
// end::configureAuthenticator[] | ||
} | ||
Comment on lines
+59
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels like these should not be split. Would be better if you can write a full snippet of code that would work in the most common case. |
||
|
||
@SuppressWarnings("unchecked") | ||
public void accessClaims() | ||
{ | ||
Request request = new Request.Wrapper(null); | ||
|
||
// tag::accessClaims[] | ||
Map<String, Object> claims = (Map<String, Object>)request.getSession(true).getAttribute("org.eclipse.jetty.security.openid.claims"); | ||
String userId = (String)claims.get("sub"); | ||
|
||
Map<String, Object> response = (Map<String, Object>)request.getSession(true).getAttribute("org.eclipse.jetty.security.openid.response"); | ||
String accessToken = (String)response.get("access_token"); | ||
// tag::accessClaims[] | ||
} | ||
|
||
public void wrappedLoginService() | ||
{ | ||
// tag::wrappedLoginService[] | ||
// Use the optional LoginService for Roles. | ||
LoginService wrappedLoginService = createWrappedLoginService(); | ||
LoginService loginService = new OpenIdLoginService(openIdConfig, wrappedLoginService); | ||
// end::wrappedLoginService[] | ||
} | ||
|
||
private LoginService createWrappedLoginService() | ||
{ | ||
HashLoginService loginService = new HashLoginService(); | ||
UserStore userStore = new UserStore(); | ||
userStore.addUser("admin", Credential.getCredential("password"), new String[]{"admin"}); | ||
loginService.setUserStore(userStore); | ||
loginService.setName(ISSUER); | ||
return loginService; | ||
} | ||
Comment on lines
+98
to
+106
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code seems important, but it is not showed in the documentation. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -858,3 +858,14 @@ The module properties are: | |
---- | ||
include::{jetty-home}/modules/well-known.mod[tags=documentation] | ||
---- | ||
|
||
[[openid]] | ||
== Module `openid` | ||
|
||
The openid module enables support for OpenID Connect (OIDC) authentication in Jetty. | ||
It allows Jetty to authenticate users via an OpenID Connect identity provider, making it possible to integrate features like "Sign in with Google" or "Sign in with Microsoft," among others. | ||
This simplifies user authentication while leveraging the security and convenience of external identity providers. | ||
|
||
---- | ||
include::{jetty-home}/modules/openid.mod[tags=documentation] | ||
---- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have a minimal discussion about the most important, or mandatory, properties. See for example the |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// | ||
// ======================================================================== | ||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
// which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
// ======================================================================== | ||
// | ||
|
||
[[openid-support]] | ||
= OpenID Support | ||
|
||
For more information about Jetty OpenID configuration also see the xref:programming-guide:security/openid-support.adoc[OpenID Support] section in the programming guide. | ||
|
||
== OpenID Provider Configuration | ||
To enable OpenID support, you first need to activate the `openid` module in your implementation. | ||
|
||
---- | ||
$ java -jar $JETTY_HOME/start.jar --add-to-start=openid | ||
---- | ||
|
||
To configure OpenID Authentication with Jetty you will need to specify the OpenID Provider's issuer identifier (case-sensitive URL using the `https` scheme) and the OAuth 2.0 Client ID and Client Secret. | ||
If the OpenID Provider does not allow metadata discovery you will also need to specify the token endpoint and authorization endpoint of the OpenID Provider. | ||
These can be set as properties in the `start.ini` or `start.d/openid.ini` files. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make an example of the |
||
|
||
== WebApp Specific Configuration in web.xml | ||
|
||
The `web.xml` file needs some specific configuration to use OpenID. | ||
There must be a `login-config` element with an `auth-method` value of `OPENID`, and a `realm-name` value of the exact URL string used to set the OpenID Provider. | ||
|
||
To set the error page, an init param is set at `"org.eclipse.jetty.security.openid.error_page"`, its value should be a path relative to the webapp where authentication errors should be redirected. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This paragraph says that the error page is an |
||
|
||
Example: | ||
|
||
[,xml,subs=attributes+] | ||
---- | ||
<login-config> | ||
<auth-method>OPENID</auth-method> | ||
<realm-name>https://accounts.google.com</realm-name> | ||
</login-config> | ||
<context-param> | ||
<param-name>org.eclipse.jetty.security.openid.error_page</param-name> | ||
<param-value>/error</param-value> | ||
</context-param> | ||
---- | ||
|
||
== Supporting Multiple OpenID Providers. | ||
|
||
You may override the `jetty-openid.xml` file in `$JETTY_BASE/etc/jetty-openid.xml` to add additional `OpenIdConfiguration` instances as beans on the server. | ||
If there are multiple OpenID configuration instances found on the server then the `OpenIdAuthenticationFactory` will select the one with an `issuer` matching the `<realm-name>` of the `web.xml` for a given web app. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I won't do it in this way, but rather as a custom module. See The idea is that you do not modify |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// | ||
// ======================================================================== | ||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
// which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
// ======================================================================== | ||
// | ||
|
||
[[openid-support]] | ||
= OpenID Support | ||
|
||
== External Setup | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's this empty section? What exactly means "external" here? This is the place where we want to have a link to Wikipedia, and describe OpenID in a little more details. If an external setup is a required setup, it should be described as such, like "OpenID requires you to configure an external identity provider, in addition to local configuration. To configure the external identity provider, you need ..." |
||
|
||
=== Registering an App with OpenID Provider | ||
You must register the app with an OpenID Provider such as link:https://developers.google.com/identity/protocols/OpenIDConnect[Google] or link:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html[Amazon]. | ||
This will give you a Client ID and Client Secret. | ||
Once set up you must also register all the possible URI's for your webapp with the path `/j_security_check` so that the OpenId Provider will allow redirection back to the webapp. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not clear? Isn't there just one URI, that ends with If there is more than one, needs a more elaborate example, such as: "Let's assume your web application deploys at |
||
|
||
These may look like | ||
|
||
* `http://localhost:8080/openid-webapp/j_security_check` | ||
|
||
* `https://example.com/j_security_check` | ||
|
||
|
||
== Embedded Configuration | ||
|
||
=== Define the `OpenIdConfiguration` for a specific OpenID Provider. | ||
|
||
If the OpenID Provider allows metadata discovery then you can use. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These examples are largely incomplete, as users would have no idea what to do with an instance of It would be better to have a full example first for the case of metadata discovery, that shows the code that allocates the Then in the other sections you can just refer to the example saying: "In this case, the |
||
|
||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=createConfigurationWithDiscovery] | ||
---- | ||
|
||
Otherwise, you can manually enter the necessary information: | ||
|
||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=createConfiguration] | ||
---- | ||
|
||
=== Configuring an `OpenIdLoginService` | ||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=configureLoginService] | ||
---- | ||
|
||
=== Configuring an `OpenIdAuthenticator` with `OpenIdConfiguration` and Error Page Redirect | ||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=configureAuthenticator] | ||
---- | ||
|
||
=== Usage | ||
|
||
==== Claims and Access Token | ||
Claims about the user can be found using attributes on the session attribute `"org.eclipse.jetty.security.openid.claims"`, and the full response containing the OAuth 2.0 Access Token can be found with the session attribute `"org.eclipse.jetty.security.openid.response"`. | ||
|
||
Example: | ||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=configureAuthenticator] | ||
---- | ||
|
||
== Scopes | ||
The OpenID scope is always used but additional scopes can be requested which can give you additional resources or privileges. | ||
For the Google OpenID Provider it can be useful to request the scopes `profile` and `email` which will give you additional user claims. | ||
|
||
Additional scopes can be requested through the `start.ini` or `start.d/openid.ini` files, or with `OpenIdConfiguration.addScopes(...);` in embedded code. | ||
|
||
== Authorization | ||
|
||
If security roles are required they can be configured through a wrapped `LoginService` which is deferred to for role information by the `OpenIdLoginService`. | ||
|
||
This can be configured in XML through `etc/openid-baseloginservice.xml` in the Distribution, or in embedded code using the constructor for the `OpenIdLoginService`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be split: the section about operation in the operations guide, and the section about code here. |
||
|
||
[,java,indent=0] | ||
---- | ||
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/OpenIdDocs.java[tags=wrappedLoginService] | ||
---- | ||
|
||
When using authorization roles, the setting `authenticateNewUsers` becomes significant. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What class has |
||
If set to `true` users not found by the wrapped `LoginService` will still be authenticated but will have no roles. | ||
If set to `false` those users will be not be allowed to authenticate and are redirected to the error page. | ||
This setting is configured through the property `jetty.openid.authenticateNewUsers` in the `start.ini` or `start.d/openid.ini` file, or with `OpenIdLoginService.setAuthenticateNewUsers(...);` in embedded code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make examples for these constants?
For example: