feat: Validate Google, Azure, OIDC SSO access (#3590)

* chore: Store expiresAt on UserAuthentications. This represents the time that the accessToken is no longer valid and should be exchanged using the refreshToken

* feat: Check and expire Google SSO

* fix: Better handling of multiple auth methods
Added more docs

* fix: Retry access validation with network errors

* Small refactor, add Azure token validation support

* doc

* test

* lint

* OIDC refresh support

* CheckSSOAccessTask -> ValidateSSOAccessTask
Added lastValidatedAt column
Skip checks if validated within 5min
Some edge cases around encrypted columns
This commit is contained in:
Tom Moor
2022-06-05 13:18:51 -07:00
committed by GitHub
parent c4c5b6289e
commit 728790e38f
19 changed files with 413 additions and 14 deletions

View File

@@ -39,7 +39,7 @@ if (env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET) {
req: Request,
accessToken: string,
refreshToken: string,
params: { id_token: string },
params: { expires_in: number; id_token: string },
_profile: Profile,
done: (
err: Error | null,
@@ -105,6 +105,7 @@ if (env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET) {
providerId: profile.oid,
accessToken,
refreshToken,
expiresIn: params.expires_in,
scopes,
},
});

View File

@@ -49,6 +49,7 @@ if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
req: Request,
accessToken: string,
refreshToken: string,
params: { expires_in: number },
profile: GoogleProfile,
done: (
err: Error | null,
@@ -85,6 +86,7 @@ if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
providerId: profile.id,
accessToken,
refreshToken,
expiresIn: params.expires_in,
scopes,
},
});

View File

@@ -3,7 +3,7 @@ import { sortBy } from "lodash";
import { signin } from "@shared/utils/urlHelpers";
import { requireDirectory } from "@server/utils/fs";
interface AuthenicationProvider {
interface AuthenticationProviderConfig {
id: string;
name: string;
enabled: boolean;
@@ -11,7 +11,7 @@ interface AuthenicationProvider {
router: Router;
}
const providers: AuthenicationProvider[] = [];
const providers: AuthenticationProviderConfig[] = [];
requireDirectory(__dirname).forEach(([module, id]) => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'config' does not exist on type 'unknown'... Remove this comment to see the full error message

View File

@@ -3,13 +3,16 @@ import { Request } from "koa";
import Router from "koa-router";
import { get } from "lodash";
import { Strategy } from "passport-oauth2";
import accountProvisioner from "@server/commands/accountProvisioner";
import accountProvisioner, {
AccountProvisionerResult,
} from "@server/commands/accountProvisioner";
import env from "@server/env";
import {
OIDCMalformedUserInfoError,
AuthenticationError,
} from "@server/errors";
import passportMiddleware from "@server/middlewares/passport";
import { User } from "@server/models";
import { StateStore, request } from "@server/utils/passport";
const router = new Router();
@@ -60,8 +63,13 @@ if (env.OIDC_CLIENT_ID && env.OIDC_CLIENT_SECRET) {
req: Request,
accessToken: string,
refreshToken: string,
params: { expires_in: number },
profile: Record<string, string>,
done: any
done: (
err: Error | null,
user: User | null,
result?: AccountProvisionerResult
) => void
) {
try {
if (!profile.email) {
@@ -102,6 +110,7 @@ if (env.OIDC_CLIENT_ID && env.OIDC_CLIENT_SECRET) {
providerId: profile.sub,
accessToken,
refreshToken,
expiresIn: params.expires_in,
scopes,
},
});

View File

@@ -66,6 +66,7 @@ if (env.SLACK_CLIENT_ID && env.SLACK_CLIENT_SECRET) {
req: Request,
accessToken: string,
refreshToken: string,
params: { expires_in: number },
profile: SlackProfile,
done: (
err: Error | null,
@@ -94,6 +95,7 @@ if (env.SLACK_CLIENT_ID && env.SLACK_CLIENT_SECRET) {
providerId: profile.user.id,
accessToken,
refreshToken,
expiresIn: params.expires_in,
scopes,
},
});