Skip to content

OpenID Connect Authentication#4038

Merged
joakime merged 13 commits intojetty-9.4.xfrom
jetty-9.4.x-OpenId
Sep 13, 2019
Merged

OpenID Connect Authentication#4038
joakime merged 13 commits intojetty-9.4.xfrom
jetty-9.4.x-OpenId

Conversation

@lachlan-roberts
Copy link
Copy Markdown
Contributor

@lachlan-roberts lachlan-roberts commented Aug 29, 2019

Allow webapps to authenticate users using the OpenId Connect (OIDC) protocol based on OAuth 2.0. This can be done with any OpenId Provider supporting OIDC. For example by using googles OIDC service you can authenticate with your webapp using your google account.

I have tested authentication with Google, Microsoft and Yahoo so far.

See #137

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
improved comments

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
@lachlan-roberts
Copy link
Copy Markdown
Contributor Author

OpenID Configuration

To configure OpenID Authentication with Jetty you need to specify the OpenID Provider, Client ID and Client Secret. These can be set as properties in the start.ini or start.d/openid.ini files.

OpenID Provider

The OpenID Provider must be an OAuth 2.0 Authentication Server which implements OpenID Connect. To use the jetty-openid module you must input the URL for the OpenID Provider you wish to use.

Examples:

Registering App with OpenID Provider

You must register an app with the OpenID provider which 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.

for example these may look like

  • http://localhost:8080/openid-webapp/j_security_check
  • https://mywebsite.com/j_security_check

WebApp Specific Configuration

The webapp should be deployed with a jetty deployable descriptor XML file to configure the security handler with the error page and OpenIdAuthenticatorFactory.

The security handler should be given an init param for "org.eclipse.jetty.security.openid.error_page" with a path relative to the webapp where authentication errors should be redirected.

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Set name="contextPath">/myapp</Set>
    <Set name="war"><SystemProperty name="myapp.home"/>/myapp.war</Set>
    <Get name="securityHandler">
        <Call name="setInitParameter">
            <Arg>org.eclipse.jetty.security.openid.error_page</Arg>
            <Arg>/error</Arg>
        </Call>
        <Set name="authenticatorFactory">
            <New class="org.eclipse.jetty.security.openid.OpenIdAuthenticatorFactory"/>
        </Set>
    </Get>
</Configure>

Claims

Claims provide the application with details about the user, such as sub (unique id), name and email.

Once a user has been authenticated you can retrieve these claims can be accessed via a Session attribute.

Map<String, Object> userInfo = (Map)request.getSession().getAttribute("org.eclipse.jetty.security.openid.user_claims"); 

Scopes

Scopes can be used to request additional resources it needs about the user such as additional user claims.

For the Google OpenID Provider it can be useful to request the scopes profile and email which can give you additional user claims such as email, email_verified and picture.

web.xml

To use OpenID authentication the web.xml file must have the login-config element with an auth method value of OPENID.

The realm name must be set to the exact URL string used to set the OpenID Provider.

Example:

<login-config>
  <auth-method>OPENID</auth-method>
  <realm-name>https://accounts.google.com/</realm-name>
</login-config>

@lachlan-roberts
Copy link
Copy Markdown
Contributor Author

@WalkerWatch can you help with the documentation for this

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
# jetty.openid.openIdProvider=https://accounts.google.com/

## The Client Identifier
# jetty.openid.clientId=1051168419525-5nl60mkugb77p9j194mrh287p1e0ahfi.apps.googleusercontent.com
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this some fake ID or a real one? You don't want to put here a real ID!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were real for my testing app, but I will change to fake ones.
The client secret can be reset easily so didn't think it was a big deal if it was real while testing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and now that a real one has been published, you will need to revoke that from your account, otherwise anybody can start using your account for auth! Low risk I know, but good practise to always cancel any credentials that have been published accidentally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client secrets have been reset.
Except for on Yahoo because the site is so bugged I cannot reset the secret, delete the app, or contact support without errors.

# jetty.openid.clientId=1051168419525-5nl60mkugb77p9j194mrh287p1e0ahfi.apps.googleusercontent.com

## The Client Secret
# jetty.openid.clientSecret=XT_MIsSv_aUCGollauCaJY8S
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fake or real?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to fake

public static final String __J_POST = "org.eclipse.jetty.security.openid.POST";
public static final String __J_METHOD = "org.eclipse.jetty.security.openid.METHOD";
public static final String __CSRF_TOKEN = "org.eclipse.jetty.security.openid.csrf_token";
public static final String __J_SECURITY_CHECK = "/j_security_check";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get rid of the __ in front of public constants.
Why are these public?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the __ parts.
This was based off the FormAuthenticator where all the constants are prefixed with __ and are public.

* If true, uris that cause a redirect to a login page will always
* be remembered. If false, only the first uri that leads to a login
* page redirect is remembered.
* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=379909
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this URL to a old issue tracking system? Remove it.

}
}


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too many empty lines!

}

InputStream content = (InputStream)connection.getContent();
return (Map)JSON.parse(IO.toString(content));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are leaking the connection open.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the InputStream to be used with a try.
Or do I need to explicitly call connection.disconnect()?

import java.io.Serializable;
import java.security.Principal;

public class OpenIdUserPrincipal implements Principal, Serializable
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No point in making this class Serializable when its only field _credentials is not serializable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the Serializable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So how is this auth going to work in a cluster? If we have a non sticky load balancer, we need the authentication to move with the session - hence it needs to be serializable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made OpenIdUserPrincipal, OpenIdCredentials and OpenIdConfiguration all Serializable. So now the SessionAuthentication used will allow the authentication to move with the session in a clustered environment.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Copy link
Copy Markdown
Contributor

@gregw gregw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to consider the clustered behaviour of this. @janbartel can you assist.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
@gregw gregw mentioned this pull request Sep 11, 2019
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
@lachlan-roberts
Copy link
Copy Markdown
Contributor Author

@sbordet can I get a re-review

Review and code cleanups.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
@joakime joakime merged commit e013c24 into jetty-9.4.x Sep 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants