feat: map preferred_username claim to user record (#2569)
This commit is contained in:
@ -89,6 +89,10 @@ OIDC_AUTH_URI=
|
|||||||
OIDC_TOKEN_URI=
|
OIDC_TOKEN_URI=
|
||||||
OIDC_USERINFO_URI=
|
OIDC_USERINFO_URI=
|
||||||
|
|
||||||
|
# Specify which claims to derive user information from
|
||||||
|
# Supports any valid JSON path with the JWT payload
|
||||||
|
OIDC_USERNAME_CLAIM=preferred_username
|
||||||
|
|
||||||
# Display name for OIDC authentication
|
# Display name for OIDC authentication
|
||||||
OIDC_DISPLAY_NAME=OpenID Connect
|
OIDC_DISPLAY_NAME=OpenID Connect
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ type Props = {|
|
|||||||
name: string,
|
name: string,
|
||||||
email: string,
|
email: string,
|
||||||
avatarUrl?: string,
|
avatarUrl?: string,
|
||||||
|
username?: string,
|
||||||
|},
|
|},
|
||||||
team: {|
|
team: {|
|
||||||
name: string,
|
name: string,
|
||||||
@ -74,6 +75,7 @@ export default async function accountProvisioner({
|
|||||||
const result = await userCreator({
|
const result = await userCreator({
|
||||||
name: userParams.name,
|
name: userParams.name,
|
||||||
email: userParams.email,
|
email: userParams.email,
|
||||||
|
username: userParams.username,
|
||||||
isAdmin: isNewTeam,
|
isAdmin: isNewTeam,
|
||||||
avatarUrl: userParams.avatarUrl,
|
avatarUrl: userParams.avatarUrl,
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
|
@ -32,6 +32,7 @@ describe("accountProvisioner", () => {
|
|||||||
name: "Jenny Tester",
|
name: "Jenny Tester",
|
||||||
email: "jenny@example.com",
|
email: "jenny@example.com",
|
||||||
avatarUrl: "https://example.com/avatar.png",
|
avatarUrl: "https://example.com/avatar.png",
|
||||||
|
username: "jtester",
|
||||||
},
|
},
|
||||||
team: {
|
team: {
|
||||||
name: "New team",
|
name: "New team",
|
||||||
@ -57,6 +58,7 @@ describe("accountProvisioner", () => {
|
|||||||
expect(auth.scopes[0]).toEqual("read");
|
expect(auth.scopes[0]).toEqual("read");
|
||||||
expect(team.name).toEqual("New team");
|
expect(team.name).toEqual("New team");
|
||||||
expect(user.email).toEqual("jenny@example.com");
|
expect(user.email).toEqual("jenny@example.com");
|
||||||
|
expect(user.username).toEqual("jtester");
|
||||||
expect(isNewUser).toEqual(true);
|
expect(isNewUser).toEqual(true);
|
||||||
expect(isNewTeam).toEqual(true);
|
expect(isNewTeam).toEqual(true);
|
||||||
expect(mailer.sendTemplate).toHaveBeenCalled();
|
expect(mailer.sendTemplate).toHaveBeenCalled();
|
||||||
@ -73,6 +75,7 @@ describe("accountProvisioner", () => {
|
|||||||
const authentications = await existing.getAuthentications();
|
const authentications = await existing.getAuthentications();
|
||||||
const authentication = authentications[0];
|
const authentication = authentications[0];
|
||||||
const newEmail = "test@example.com";
|
const newEmail = "test@example.com";
|
||||||
|
const newUsername = "tname";
|
||||||
|
|
||||||
const { user, isNewUser, isNewTeam } = await accountProvisioner({
|
const { user, isNewUser, isNewTeam } = await accountProvisioner({
|
||||||
ip,
|
ip,
|
||||||
@ -80,6 +83,7 @@ describe("accountProvisioner", () => {
|
|||||||
name: existing.name,
|
name: existing.name,
|
||||||
email: newEmail,
|
email: newEmail,
|
||||||
avatarUrl: existing.avatarUrl,
|
avatarUrl: existing.avatarUrl,
|
||||||
|
username: newUsername,
|
||||||
},
|
},
|
||||||
team: {
|
team: {
|
||||||
name: existingTeam.name,
|
name: existingTeam.name,
|
||||||
@ -102,6 +106,7 @@ describe("accountProvisioner", () => {
|
|||||||
expect(auth.scopes.length).toEqual(1);
|
expect(auth.scopes.length).toEqual(1);
|
||||||
expect(auth.scopes[0]).toEqual("read");
|
expect(auth.scopes[0]).toEqual("read");
|
||||||
expect(user.email).toEqual(newEmail);
|
expect(user.email).toEqual(newEmail);
|
||||||
|
expect(user.username).toEqual(newUsername);
|
||||||
expect(isNewTeam).toEqual(false);
|
expect(isNewTeam).toEqual(false);
|
||||||
expect(isNewUser).toEqual(false);
|
expect(isNewUser).toEqual(false);
|
||||||
expect(mailer.sendTemplate).not.toHaveBeenCalled();
|
expect(mailer.sendTemplate).not.toHaveBeenCalled();
|
||||||
@ -162,6 +167,7 @@ describe("accountProvisioner", () => {
|
|||||||
name: "Jenny Tester",
|
name: "Jenny Tester",
|
||||||
email: "jenny@example.com",
|
email: "jenny@example.com",
|
||||||
avatarUrl: "https://example.com/avatar.png",
|
avatarUrl: "https://example.com/avatar.png",
|
||||||
|
username: "jtester",
|
||||||
},
|
},
|
||||||
team: {
|
team: {
|
||||||
name: team.name,
|
name: team.name,
|
||||||
@ -186,6 +192,7 @@ describe("accountProvisioner", () => {
|
|||||||
expect(auth.scopes.length).toEqual(1);
|
expect(auth.scopes.length).toEqual(1);
|
||||||
expect(auth.scopes[0]).toEqual("read");
|
expect(auth.scopes[0]).toEqual("read");
|
||||||
expect(user.email).toEqual("jenny@example.com");
|
expect(user.email).toEqual("jenny@example.com");
|
||||||
|
expect(user.username).toEqual("jtester");
|
||||||
expect(isNewUser).toEqual(true);
|
expect(isNewUser).toEqual(true);
|
||||||
expect(mailer.sendTemplate).toHaveBeenCalled();
|
expect(mailer.sendTemplate).toHaveBeenCalled();
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ type UserCreatorResult = {|
|
|||||||
export default async function userCreator({
|
export default async function userCreator({
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
|
username,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
teamId,
|
teamId,
|
||||||
@ -22,6 +23,7 @@ export default async function userCreator({
|
|||||||
}: {|
|
}: {|
|
||||||
name: string,
|
name: string,
|
||||||
email: string,
|
email: string,
|
||||||
|
username?: string,
|
||||||
isAdmin?: boolean,
|
isAdmin?: boolean,
|
||||||
avatarUrl?: string,
|
avatarUrl?: string,
|
||||||
teamId: string,
|
teamId: string,
|
||||||
@ -63,7 +65,7 @@ export default async function userCreator({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
await user.update({ email });
|
await user.update({ email, username });
|
||||||
await auth.update(rest);
|
await auth.update(rest);
|
||||||
|
|
||||||
return { user, authentication: auth, isNewUser: false };
|
return { user, authentication: auth, isNewUser: false };
|
||||||
@ -128,6 +130,7 @@ export default async function userCreator({
|
|||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
|
username,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
teamId,
|
teamId,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
|
@ -13,10 +13,12 @@ describe("userCreator", () => {
|
|||||||
const authentications = await existing.getAuthentications();
|
const authentications = await existing.getAuthentications();
|
||||||
const existingAuth = authentications[0];
|
const existingAuth = authentications[0];
|
||||||
const newEmail = "test@example.com";
|
const newEmail = "test@example.com";
|
||||||
|
const newUsername = "tname";
|
||||||
|
|
||||||
const result = await userCreator({
|
const result = await userCreator({
|
||||||
name: existing.name,
|
name: existing.name,
|
||||||
email: newEmail,
|
email: newEmail,
|
||||||
|
username: newUsername,
|
||||||
avatarUrl: existing.avatarUrl,
|
avatarUrl: existing.avatarUrl,
|
||||||
teamId: existing.teamId,
|
teamId: existing.teamId,
|
||||||
ip,
|
ip,
|
||||||
@ -34,6 +36,7 @@ describe("userCreator", () => {
|
|||||||
expect(authentication.scopes.length).toEqual(1);
|
expect(authentication.scopes.length).toEqual(1);
|
||||||
expect(authentication.scopes[0]).toEqual("read");
|
expect(authentication.scopes[0]).toEqual("read");
|
||||||
expect(user.email).toEqual(newEmail);
|
expect(user.email).toEqual(newEmail);
|
||||||
|
expect(user.username).toEqual(newUsername);
|
||||||
expect(isNewUser).toEqual(false);
|
expect(isNewUser).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -101,6 +104,7 @@ describe("userCreator", () => {
|
|||||||
const result = await userCreator({
|
const result = await userCreator({
|
||||||
name: "Test Name",
|
name: "Test Name",
|
||||||
email: "test@example.com",
|
email: "test@example.com",
|
||||||
|
username: "tname",
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
ip,
|
ip,
|
||||||
authentication: {
|
authentication: {
|
||||||
@ -117,6 +121,7 @@ describe("userCreator", () => {
|
|||||||
expect(authentication.scopes.length).toEqual(1);
|
expect(authentication.scopes.length).toEqual(1);
|
||||||
expect(authentication.scopes[0]).toEqual("read");
|
expect(authentication.scopes[0]).toEqual("read");
|
||||||
expect(user.email).toEqual("test@example.com");
|
expect(user.email).toEqual("test@example.com");
|
||||||
|
expect(user.username).toEqual("tname");
|
||||||
expect(isNewUser).toEqual(true);
|
expect(isNewUser).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import passport from "@outlinewiki/koa-passport";
|
import passport from "@outlinewiki/koa-passport";
|
||||||
import fetch from "fetch-with-proxy";
|
import fetch from "fetch-with-proxy";
|
||||||
import Router from "koa-router";
|
import Router from "koa-router";
|
||||||
|
import get from "lodash/get";
|
||||||
import { Strategy } from "passport-oauth2";
|
import { Strategy } from "passport-oauth2";
|
||||||
import accountProvisioner from "../../../commands/accountProvisioner";
|
import accountProvisioner from "../../../commands/accountProvisioner";
|
||||||
import env from "../../../env";
|
import env from "../../../env";
|
||||||
@ -22,6 +23,8 @@ const OIDC_AUTH_URI = process.env.OIDC_AUTH_URI;
|
|||||||
const OIDC_TOKEN_URI = process.env.OIDC_TOKEN_URI;
|
const OIDC_TOKEN_URI = process.env.OIDC_TOKEN_URI;
|
||||||
const OIDC_USERINFO_URI = process.env.OIDC_USERINFO_URI;
|
const OIDC_USERINFO_URI = process.env.OIDC_USERINFO_URI;
|
||||||
const OIDC_SCOPES = process.env.OIDC_SCOPES || "";
|
const OIDC_SCOPES = process.env.OIDC_SCOPES || "";
|
||||||
|
const OIDC_USERNAME_CLAIM =
|
||||||
|
process.env.OIDC_USERNAME_CLAIM || "preferred_username";
|
||||||
const allowedDomains = getAllowedDomains();
|
const allowedDomains = getAllowedDomains();
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
@ -103,6 +106,9 @@ if (OIDC_CLIENT_ID) {
|
|||||||
name: profile.name,
|
name: profile.name,
|
||||||
email: profile.email,
|
email: profile.email,
|
||||||
avatarUrl: profile.picture,
|
avatarUrl: profile.picture,
|
||||||
|
// Claim name can be overriden using an env variable.
|
||||||
|
// Default is 'preferred_username' as per OIDC spec.
|
||||||
|
username: get(profile, OIDC_USERNAME_CLAIM),
|
||||||
},
|
},
|
||||||
authenticationProvider: {
|
authenticationProvider: {
|
||||||
name: providerName,
|
name: providerName,
|
||||||
|
@ -104,6 +104,7 @@ export async function buildUser(overrides: Object = {}) {
|
|||||||
{
|
{
|
||||||
email: `user${count}@example.com`,
|
email: `user${count}@example.com`,
|
||||||
name: `User ${count}`,
|
name: `User ${count}`,
|
||||||
|
username: `user${count}`,
|
||||||
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||||
lastActiveAt: new Date("2018-01-01T00:00:00.000Z"),
|
lastActiveAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||||
authentications: [
|
authentications: [
|
||||||
|
Reference in New Issue
Block a user