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

feat(userInfo): implement persisting user info to support limited tokens #24729

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

kuangp
Copy link
Member

@kuangp kuangp commented May 10, 2024

Hey, I just made a Pull Request!

Part of BEP-0003
Fixes #24420

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)
  • All your commits have a Signed-off-by line in the message. (more info)

@kuangp kuangp requested review from a team as code owners May 10, 2024 22:32
@kuangp kuangp requested review from freben and vinzscam May 10, 2024 22:32
@github-actions github-actions bot added the auth label May 10, 2024
@backstage-goalie
Copy link
Contributor

Changed Packages

Package Name Package Path Changeset Bump Current Version
@backstage/backend-app-api packages/backend-app-api patch v0.7.3-next.1
@backstage/plugin-auth-backend plugins/auth-backend patch v0.22.5-next.2

@@ -190,7 +189,7 @@ export class TokenFactory implements TokenIssuer {
alg: key.alg,
kid: key.kid,
},
payload: { sub, ent, iat, exp },
Copy link
Member Author

Choose a reason for hiding this comment

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

Did we want to remove ent from all tokens now that the user info service is flushed out or just from limited ones?

Copy link
Member

Choose a reason for hiding this comment

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

The goal is to remove it from all tokens. But we may want to keep it in there still for some time, while the userInfo usage ramps up. As long as plugins exist that look at the claim directly (via an old IdentityService for example), the data may need to stay. It's fine to make the deprecation of that field a separate effort from implementing the endpoint fully.

.comment('User entity reference');

table
.text('ownership_entity_refs', 'longtext')
Copy link
Member

Choose a reason for hiding this comment

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

An open question here (maybe @Rugvip) - should we make this one just user_info (with all json stringified info) and not storing all possible pieces of data one by one? Not sure that the service really will care about the detailed contents.

For context, we were discussing before about what to do with custom claims - why not store custom claims here too? Then where to put those?

Copy link
Member

Choose a reason for hiding this comment

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

Yep, I think we will want to store custom claims here too and make this an opaque user info blob.

Copy link
Member Author

Choose a reason for hiding this comment

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

sounds good - updated!

@sachingharge
Copy link

Any rough estimation on when this PR will be merged and part of release as it is affecting all our users (such as leaders, tech leads etc.) who are part of many ad groups?

@kuangp
Copy link
Member Author

kuangp commented Jun 5, 2024

Hey @freben @Rugvip gentle nudge here - hoping to get this into the next release 🤞

Copy link
Member

@freben freben left a comment

Choose a reason for hiding this comment

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

Alright, finally got a good look at it. Great work!

if (
!Array.isArray(ownershipEntityRefs) ||
ownershipEntityRefs.some(ref => typeof ref !== 'string')
Array.isArray(ownershipEntityRefs) &&
Copy link
Member

Choose a reason for hiding this comment

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

I think I'd rather keep the check so effectively like

let ownershipEntityRefs = ent;
if (!ownershipEntityRefs) {
  ownershipEnttityRefs = await ...;
}

if (!ownershipEntityRefs) {
  throw ...
} else if (isNotValid) {
  throw ...
}


res.json({
sub: userInfo.userEntityRef,
ent: userInfo.ownershipEntityRefs,
Copy link
Member

Choose a reason for hiding this comment

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

Regarding what's stored, and what's returned over the wire: Maybe it would simplify things if the storage model was basically { claims: JsonObject }, so that what you find in the json column would typically be like {"claims":{"sub":"user:default/freben","ent":[]}} or so. At that point, maybe the returned body could have a claims root key too? 🤔

Maybe @Rugvip has opinions here, but I'm essentially wondering if who, if anyone, should do the translations back and forth between the long-form and short-form of each name an if it's at all worth it. Especially if we then open up for people to customize what set of claims that actually get persisted, so we can get extra stuff in here that come out of the sign in resolver. And with that claims key, we could also add the profile key next to it, with what came out of the profile transform during sign in.

So - what should the ideal response object shape be here?

user_info: string;
};

// TODO: How do we prune stale users?
Copy link
Member

Choose a reason for hiding this comment

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

These should probably accept (and store) effectively the exp of the token so that they can be cleaned up automatically (after a grace period) after the token itself becomes useless. Remember, you have to present an actual valid non-expired token to be able to read out of this anyway.

// issuance so that it can be retrieved later by limited user tokens
await this.userInfoDatabaseHandler.addUserInfo({
userEntityRef: sub,
ownershipEntityRefs: ent,
Copy link
Member

Choose a reason for hiding this comment

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

So related to my comment elsewhere - i wonder if this can't just be ({ claims }) instead. Well, we may perhaps denylist some known unnecessary fields, like exp, iat, iss, aud and uip, from the body itself, but keep whatever custom stuff remains after that in addition to sub and ent.

And this is just the internal storage model; there's nothing stopping us from translating that to something else in the JSON response from the service itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

🐛 Bug Report: TechDocs cookie authentication fails due to 'cookie was too large'
4 participants