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

[Feature/Extension] Extension token handler #3034

Conversation

RyanL1997
Copy link
Collaborator

@RyanL1997 RyanL1997 commented Jul 19, 2023

Description

This PR is the refactor/modification based on @scrawfor99's previous PR(#2787) against main branch for Extension token handler. However, the scope of this PR is only for OBO related changes.

  • Category (Enhancement, New feature, Bug fix, Test fix, Refactoring, Maintenance, Documentation)
    New Feature

Issues Resolved

Check List

  • New functionality includes testing
  • New functionality has been documented
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@codecov
Copy link

codecov bot commented Jul 19, 2023

Codecov Report

Merging #3034 (8e1f399) into feature/extensions (058f8ec) will decrease coverage by 56.92%.
The diff coverage is 0.00%.

❗ Current head 8e1f399 differs from pull request most recent head 03a7875. Consider uploading reports for the commit 03a7875 to get more accurate results

@@                   Coverage Diff                    @@
##             feature/extensions   #3034       +/-   ##
========================================================
- Coverage                 62.38%   5.47%   -56.92%     
+ Complexity                 3390     222     -3168     
========================================================
  Files                       259     275       +16     
  Lines                     20044   20198      +154     
  Branches                   3371    3392       +21     
========================================================
- Hits                      12505    1105    -11400     
- Misses                     5888   18913    +13025     
+ Partials                   1651     180     -1471     
Files Changed Coverage Δ
.../opensearch/security/OpenSearchSecurityPlugin.java 10.87% <0.00%> (-73.55%) ⬇️
...y/action/onbehalf/CreateOnBehalfOfTokenAction.java 0.00% <ø> (-28.82%) ⬇️
...security/dlic/rest/api/InternalUsersApiAction.java 0.00% <0.00%> (-64.08%) ⬇️
...g/opensearch/security/dlic/rest/support/Utils.java 0.00% <0.00%> (-54.66%) ⬇️
...search/security/identity/SecurityTokenManager.java 0.00% <0.00%> (ø)
...g/opensearch/security/securityconf/impl/CType.java 0.00% <0.00%> (-100.00%) ⬇️
...search/security/user/InternalUserTokenHandler.java 0.00% <0.00%> (ø)
...java/org/opensearch/security/user/UserService.java 0.00% <0.00%> (-50.87%) ⬇️
...org/opensearch/security/user/UserTokenHandler.java 0.00% <0.00%> (ø)

... and 230 files with indirect coverage changes

@RyanL1997
Copy link
Collaborator Author

RyanL1997 commented Jul 27, 2023

Moving some of the communication between me and @scrawfor99 over here

  1. The scope of this PR should only focus on the interface of issueOnBehalfOfToken(), reference to here.
  2. For the changes that got carried over from Implements token handlers and tests  #2787, if the team thinks it is not in the scope of this PR, it is ok to remove them. I'm leaving them here for now cuz I think it is easier to continue the service account work from here.

@RyanL1997 RyanL1997 marked this pull request as ready for review July 27, 2023 23:09
@RyanL1997 RyanL1997 changed the title [Feature] Extension token handler [Feature/Extension] Extension token handler Jul 27, 2023
Copy link
Collaborator Author

@RyanL1997 RyanL1997 left a comment

Choose a reason for hiding this comment

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

Adding some additional context here:

return (exp > currentTime && !revokedTokens.exists(bearerAuthToken.getCompleteToken()));
}

public boolean validateJustInTimeToken(AuthToken authToken) {
Copy link
Collaborator Author

@RyanL1997 RyanL1997 Jul 27, 2023

Choose a reason for hiding this comment

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

The reason I make this validation is that I think we do have different expectations for obo tokens than the other bearer auth tokens. For obo tokens, according to its feature of just-in-time, we do expect the payload of iat and nbf have the same value.

long timeMillis = timeProvider.getAsLong();
Instant now = Instant.ofEpochMilli(timeProvider.getAsLong());

jwtProducer.setSignatureProvider(JwsUtils.getSignatureProvider(signingKey));
JwtClaims jwtClaims = new JwtClaims();
JwtToken jwt = new JwtToken(jwtClaims);

jwtClaims.setProperty("typ", tokenIdentifier);
Copy link
Collaborator Author

@RyanL1997 RyanL1997 Jul 27, 2023

Choose a reason for hiding this comment

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

This is the idea that can be also applied for the potential approach of handling the edge cases of OBO endpoint (see comments). By having a token type as the identifier, it will be easier for us to know if it is a obo token or not so that we can have different expectations.

If we decide to go with this design, I will also update the threat model documentation

Long iat = (Long) jwt.getClaim("iat");
Long nbf = (Long) jwt.getClaim("nbf");
Long exp = (Long) jwt.getClaim("exp");
SecurityDynamicConfiguration revokedTokens = load(getRevokedTokensConfigName(), false);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If we choose to split the validations between obo tokens and other bearer auth tokens in this way, then I don't think we need this line here, since the revocation is not in the scope of obo token. (At least for now)

@RyanL1997 RyanL1997 self-assigned this Jul 28, 2023
Copy link
Member

@cwperks cwperks left a comment

Choose a reason for hiding this comment

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

@RyanL1997 There looks to be a lot more on this PR than an implementation of issueOnBehalfOfToken. Is everything in this PR needed for the issuance of obo tokens? Can we narrow the PR to the issuance of obo tokens and have a subsequent PR address the issuance of service account tokens?

@@ -105,13 +105,16 @@ public String createJwt(
List<String> roles,
List<String> backendRoles
) throws Exception {
String tokenIdentifier = "obo";
Copy link
Member

Choose a reason for hiding this comment

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

Can this variable be called tokenType?

Sometimes JWTs include a claim called jti that is a unique identifier for a token. In my experience, systems use jti to invalidate tokens since this identifier uniquely identifies a token.


import static org.opensearch.security.dlic.rest.support.Utils.universalHash;

public class InternalUserTokenHandler implements TokenManager {
Copy link
Member

Choose a reason for hiding this comment

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

This class looks like its doing too much. In the PR description it mentions that this PR is for issueOnBehalfOfToken. Are all of these methods being utilized in this class?

Signed-off-by: Ryan Liang <[email protected]>
Comment on lines +1901 to +1907
public static DiscoveryNode getLocalNode() {
return localNode;
}

public static void setLocalNode(DiscoveryNode node) {
localNode = node;
}
Copy link
Member

Choose a reason for hiding this comment

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

this should be removed. Check this PR for more details: https://github.com/opensearch-project/security/pull/3066/files

@@ -159,6 +160,8 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C
return;
} catch (IOException ex) {
throw new IOException(ex);
} catch (NoSuchAlgorithmException e) {
Copy link
Member

Choose a reason for hiding this comment

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

Why add this catch block to then throw RuntimeException?

@Subscribe
public void onDynamicConfigModelChanged(DynamicConfigModel dcm) {
this.dcm = dcm;
if (dcm.getDynamicOnBehalfOfSettings().get("signing_key") != null
Copy link
Member

Choose a reason for hiding this comment

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

we should extract: dcm.getDynamicOnBehalfOfSettings() to a variable


return passwordGenerator.generatePassword(random.nextInt(8) + 8, rules);
private String generatePassword() {
return "superSecurePassword";
Copy link
Member

Choose a reason for hiding this comment

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

why make this change?

import java.io.IOException;
import java.util.Collections;

public class UserTokenHandler {
Copy link
Member

Choose a reason for hiding this comment

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

Is this class different that InternalUserTokenHandler in the sense that this class deals with actual user vs the other one deals with service accounts?
If so why not combine them into 1 class?

Comment on lines +62 to +66
claims = new HashMap<String, Object>() {
{
put(JwtConstants.CLAIM_AUDIENCE, "ext_0");
}
};
Copy link
Member

Choose a reason for hiding this comment

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

can write this as: Map.of(JwtConstants.CLAIM_AUDIENCE, "ext_0");

@RyanL1997 RyanL1997 closed this Aug 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants