Skip to content
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

[GEOS-10646] OAuth access tokens #6167

Merged
merged 13 commits into from
Sep 27, 2022
Merged

Conversation

davidblasby
Copy link
Contributor

@davidblasby davidblasby commented Sep 8, 2022

GEOS-10646

This PR is improving the support for Bearer Tokens. See the updated GS OpenID documentation for setup and usage.

Issue: https://osgeo-org.atlassian.net/browse/GEOS-10646

Summary: attach an Access Token to your HTTP requests - useful for automated (i.e. desktop/remote web) access of the REST api.

There was already some partial support for Bearer tokens. This PR improves it.

  1. There is now better token validation (see GS doc + OIDC specification). This improves security.
  2. Since you cannot use ID Tokens with attached access tokens, I added two new ways to get user groups:
    a) from the "userinfo" endpoint (recommended for KeyCloak)
    b) from the MS Graph API (only for MS Azure AD)
  3. There is a configuration on the OIDC web page to turn on/off bearer tokens
  4. I added some minor validation to the OIDC web page
  5. Added a few test cases
  6. Updated documentation for Attached Bearer Tokens
  7. Tested with Keycloak and Azure AD
  8. I attach the "userinfo" results to the incomming request (in the same manner as the ID/Access tokens + other spring stuff)
  9. I attach a flag to the incomming request indicating if the authentication is BEARER or USER (in the same manner as the ID/Access tokens + other spring stuff)

Checklist

For core and extension modules:

  • New unit tests have been added covering the changes.
  • Documentation has been updated (if change is visible to end users).
  • [n/a] The REST API docs have been updated (when changing configuration objects or the REST controllers).
  • [GEOS-10646] There is an issue in the GeoServer Jira (except for changes that do not affect administrators or end users in any way).
  • [squash on merge] Commit message(s) must be in the form [GEOS-XYZWV] Title of the Jira ticket.
  • Bug fixes and small new features are presented as a single commit.
  • Each commit has a single objective (if there are multiple commits, each has a separate JIRA ticket describing its goal).

@jodygarnett jodygarnett changed the title Accesstokens [GEOS-10646] OAuth access tokens Sep 8, 2022
// LOGGER.log(Level.FINE, "ID token: " + (String)
// request.getAttribute(ID_TOKEN_VALUE));
// } catch (Exception e) {
// }
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the comments; this is the rare case where keeping commented out code in the codebase may be worthwhile.

Copy link
Member

Choose a reason for hiding this comment

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

One trick I do is to do an:

private static boolean DEBUGGING = false;

if (DEBUGGING) {
   // some stuff that would otherwise be commented out
}

May have to do a PMD ignore to get that passed QA checks but at least the debugging code will still be compiled.

import org.geoserver.security.oauth2.OpenIdConnectFilterConfig;

/**
* This is a simple token validator that runs a list of TokenValidators. This doesn't do any
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* This is a simple token validator that runs a list of TokenValidators. This doesn't do any
* This is a token validator that runs a list of TokenValidators. This doesn't do any

Copy link
Member

@jodygarnett jodygarnett left a comment

Choose a reason for hiding this comment

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

I appreciate the TokenValidator interface and classes. I would like one of the other teams using OAuth to review (but I understand they may not be interested in bearer tokens at this time).

@jodygarnett
Copy link
Member

jodygarnett commented Sep 13, 2022

Update from today's meeting:

  • Ask @taba90 or @afabiani to review due to number of files changes
  • Double check tests have been run locally, since some tests already extract credentials

Copy link
Contributor

@taba90 taba90 left a comment

Choose a reason for hiding this comment

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

Overall looks good, tests passed running them locally. I've done some tests and it works fine.
I've added some minor comments.

try {
memberOfEndpoint = new URL("https://graph.microsoft.com/v1.0/me/memberOf");
} catch (MalformedURLException e) {
e.printStackTrace();
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
e.printStackTrace();
e.printStackTrace();

please remove printStackTrace();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

made it log (shouldn't throw unless someone makes a type on the above line)

Comment on lines 203 to 246

List<GeoServerRole> result = new ArrayList<>();
if (o instanceof String) {
result.add(new GeoServerRole((String) o));
} else if (o instanceof List) {
((List) o).stream().forEach(v -> result.add(new GeoServerRole((String) v)));
} else {
LOGGER.log(
Level.FINE,
"Did not find "
+ rolesAttributePath
+ " in the token, returning an empty role list");
}
if (!result.isEmpty()) {
enrichWithRoleCalculator(result);
}
return result;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

this piece of code seems equal to the one in the getRolesFromToken method. Maybe extracting common parts in a separate method would be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactored


String rolesAttributePath =
((OpenIdConnectFilterConfig) this.filterConfig).getTokenRolesClaim();
Object o = JsonPath.read(userinfoMap, rolesAttributePath);
Copy link
Contributor

@taba90 taba90 Sep 15, 2022

Choose a reason for hiding this comment

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

I would catch this since if the attribute is not present this will throw exception blocking the user to be authenticated ( it will not throw an IOException catched in the OAuth2Filter superclass). It should be fine to just reuse the extracFromJSON static method above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created another extractFromJSON(), based on Map (instead of a JSON string).

@@ -19,11 +19,14 @@ public class OpenIdConnectFilterConfig extends GeoServerOAuth2FilterConfig {
String tokenRolesClaim;
String responseMode;
boolean sendClientSecret = false;
boolean allowBearerTokens = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Since bearer authentication was already working although without validation of the token, maybe this flag could be kept as true by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed it to true. I was a bit worried leaving bearer tokens as the default.

@davidblasby
Copy link
Contributor Author

@taba90 - thanks for the review!

david.blasby and others added 13 commits September 20, 2022 08:55
Co-authored-by: Jody Garnett <jody.garnett@gmail.com>
…nect-core/src/main/java/org/geoserver/security/oauth2/MSGraphRolesResolver.java

Co-authored-by: Jody Garnett <jody.garnett@gmail.com>
…nect-core/src/main/java/org/geoserver/security/oauth2/OpenIdConnectAuthenticationFilter.java

Co-authored-by: Jody Garnett <jody.garnett@gmail.com>
…nect-core/src/main/java/org/geoserver/security/oauth2/OpenIdConnectAuthenticationProvider.java

Co-authored-by: Jody Garnett <jody.garnett@gmail.com>
@davidblasby
Copy link
Contributor Author

FYI - rebased due to test case failure (not to do with this pr)

@davidblasby
Copy link
Contributor Author

@taba90 - ready to merge?

Copy link
Contributor

@taba90 taba90 left a comment

Choose a reason for hiding this comment

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

looks good to me, merging...

@taba90 taba90 merged commit 67e2792 into geoserver:main Sep 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants