fix microsoft auth and ingestion for users without defined email
Signed-off-by: Jessica He <jhe@redhat.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-microsoft-provider': minor
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Allow users without defined email to be ingested by the `msgraph` catalog plugin and add `userIdMatchingUserEntityAnnotation` sign-in resolver for the Microsoft auth provider to support sign-in for users without defined email.
|
||||
@@ -32,5 +32,9 @@ export namespace microsoftSignInResolvers {
|
||||
OAuthAuthenticatorResult<PassportProfile>,
|
||||
unknown
|
||||
>;
|
||||
const userIdMatchingUserEntityAnnotation: SignInResolverFactory<
|
||||
OAuthAuthenticatorResult<PassportProfile>,
|
||||
unknown
|
||||
>;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
*/
|
||||
export namespace microsoftSignInResolvers {
|
||||
/**
|
||||
* Looks up the user by matching their Microsoft username to the entity name.
|
||||
* Looks up the user by matching their Microsoft email to the email entity annotation.
|
||||
*/
|
||||
export const emailMatchingUserEntityAnnotation = createSignInResolverFactory({
|
||||
create() {
|
||||
@@ -50,4 +50,31 @@ export namespace microsoftSignInResolvers {
|
||||
};
|
||||
},
|
||||
});
|
||||
/**
|
||||
* Looks up the user by matching their Microsoft user id to the user id entity annotation.
|
||||
*/
|
||||
export const userIdMatchingUserEntityAnnotation = createSignInResolverFactory(
|
||||
{
|
||||
create() {
|
||||
return async (
|
||||
info: SignInInfo<OAuthAuthenticatorResult<PassportProfile>>,
|
||||
ctx,
|
||||
) => {
|
||||
const { result } = info;
|
||||
|
||||
const id = result.fullProfile.id;
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Microsoft profile contained no id');
|
||||
}
|
||||
|
||||
return ctx.signInWithCatalogUser({
|
||||
annotations: {
|
||||
'graph.microsoft.com/user-id': id,
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -533,6 +533,7 @@ export const providers: Readonly<{
|
||||
resolvers: Readonly<{
|
||||
emailMatchingUserEntityProfileEmail: () => SignInResolver_2<OAuthResult>;
|
||||
emailLocalPartMatchingUserEntityName: () => SignInResolver_2<OAuthResult>;
|
||||
userIdMatchingUserEntityAnnotation: () => SignInResolver_2<OAuthResult>;
|
||||
emailMatchingUserEntityAnnotation: () => SignInResolver_2<OAuthResult>;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
@@ -65,5 +65,7 @@ export const microsoft = createAuthProviderIntegration({
|
||||
commonSignInResolvers.emailMatchingUserEntityProfileEmail(),
|
||||
emailMatchingUserEntityAnnotation:
|
||||
microsoftSignInResolvers.emailMatchingUserEntityAnnotation(),
|
||||
userIdMatchingUserEntityAnnotation:
|
||||
microsoftSignInResolvers.userIdMatchingUserEntityAnnotation(),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -90,4 +90,31 @@ describe('defaultTransformers', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('tests defaultUserTransformer with no email', async () => {
|
||||
const user: MicrosoftGraph.User = {
|
||||
id: 'foo',
|
||||
displayName: 'BAR',
|
||||
userPrincipalName: 'test@upn',
|
||||
};
|
||||
const userPhoto = 'test_photo';
|
||||
const result = await defaultUserTransformer(user, userPhoto);
|
||||
expect(result).toEqual({
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'graph.microsoft.com/user-id': 'foo',
|
||||
},
|
||||
name: 'test_upn',
|
||||
},
|
||||
spec: {
|
||||
memberOf: [],
|
||||
profile: {
|
||||
displayName: 'BAR',
|
||||
picture: 'test_photo',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -122,25 +122,25 @@ export async function defaultUserTransformer(
|
||||
user: MicrosoftGraph.User,
|
||||
userPhoto?: string,
|
||||
): Promise<UserEntity | undefined> {
|
||||
if (!user.id || !user.displayName || !user.mail) {
|
||||
if (!user.id || !user.displayName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const name = normalizeEntityName(user.mail);
|
||||
const name = user.mail
|
||||
? normalizeEntityName(user.mail)
|
||||
: normalizeEntityName(user.userPrincipalName!);
|
||||
const entity: UserEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
name,
|
||||
annotations: {
|
||||
[MICROSOFT_EMAIL_ANNOTATION]: user.mail!,
|
||||
[MICROSOFT_GRAPH_USER_ID_ANNOTATION]: user.id!,
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
profile: {
|
||||
displayName: user.displayName!,
|
||||
email: user.mail!,
|
||||
|
||||
// TODO: Additional fields?
|
||||
// jobTitle: user.jobTitle || undefined,
|
||||
@@ -151,6 +151,11 @@ export async function defaultUserTransformer(
|
||||
},
|
||||
};
|
||||
|
||||
if (user.mail) {
|
||||
entity.metadata.annotations![MICROSOFT_EMAIL_ANNOTATION] = user.mail;
|
||||
entity.spec.profile!.email = user.mail;
|
||||
}
|
||||
|
||||
if (userPhoto) {
|
||||
entity.spec.profile!.picture = userPhoto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user