mirror of
https://github.com/dadosfera/maestro.git
synced 2026-11-14 12:29:08 +00:00
REFACTOR: openid module
This commit is contained in:
@@ -53,7 +53,6 @@ import jwt from 'jsonwebtoken';
|
||||
import { LanguageEnum } from 'src/utils/languages.enum';
|
||||
import { Language } from 'src/decorators/language.decorator';
|
||||
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
|
||||
import { CreatedIdentityProvider, CreateIdentityProvider } from './dtos/openid';
|
||||
|
||||
@ApiTags('Auth')
|
||||
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
|
||||
@@ -111,56 +110,6 @@ export class AuthController {
|
||||
return this.authClient.refreshAccessToken({ refreshToken }, metadata);
|
||||
}
|
||||
|
||||
@Post('/idp')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOkResponse({ type: CreatedIdentityProvider })
|
||||
async addIdentityProvider(
|
||||
@User() user: RequestUser,
|
||||
@Body() body: IdProvider,
|
||||
@Language() language: LanguageEnum,
|
||||
) {
|
||||
this.logger.info('/auth - RefreshAccessToken');
|
||||
|
||||
const metadata = PackTheMetadata({
|
||||
customer_id: user.customer_id,
|
||||
language,
|
||||
});
|
||||
|
||||
return this.authClient.createIdentityProvider(body, metadata);
|
||||
}
|
||||
|
||||
@Get('/idp/:name')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Redirect()
|
||||
async loginIdp(
|
||||
@Body() body: { name: string },
|
||||
@Req() req: Request,
|
||||
) {
|
||||
this.logger.info('/auth - RefreshAccessToken');
|
||||
|
||||
const redirectUrl = this.authClient.loginIdp(body.name, req);
|
||||
return {
|
||||
url: redirectUrl,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('/idp/:name/callback')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOkResponse({ type: AuthRefreshAccessTokenRes })
|
||||
@Redirect()
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.SNOWFLAKE.permissions.OPEN)
|
||||
async callbackIdp(
|
||||
@Param('name') name: string,
|
||||
@Req() req: Request,
|
||||
) {
|
||||
this.logger.info('/auth - RefreshAccessToken');
|
||||
|
||||
const redirectUrl = this.authClient.authorizeIdp(name, req);
|
||||
return {
|
||||
url: redirectUrl,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
@Post('/sso/snowflake')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.SNOWFLAKE.permissions.OPEN)
|
||||
|
||||
@@ -17,12 +17,10 @@ import {
|
||||
AuthResetPasswordRequest,
|
||||
AuthVerifyResetPasswordCodeRequest,
|
||||
AuthConfirmResetPasswordRequest,
|
||||
IdProvider,
|
||||
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { Metadata } from '@grpc/grpc-js';
|
||||
import * as client from 'openid-client'
|
||||
import { Request } from 'express';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AuthClientService implements OnModuleInit {
|
||||
@@ -180,84 +178,5 @@ export class AuthClientService implements OnModuleInit {
|
||||
);
|
||||
}
|
||||
|
||||
createIdentityProvider(body: IdProvider, metadata: Metadata) {
|
||||
return lastValueFrom(
|
||||
this.identityProviderService.CreateIdentityProvider(body, metadata),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async loginIdp(name: string, req: Request) {
|
||||
const idp = await lastValueFrom(
|
||||
this.identityProviderService.FindIdentityProvider({ name }),
|
||||
);
|
||||
|
||||
const config: client.Configuration = await client.discovery(
|
||||
new URL(idp.issueUrl),
|
||||
idp.clientId,
|
||||
idp.clientSecret,
|
||||
)
|
||||
|
||||
const redirect_uri = `http://localhost:3000/auth/idp/${name}/callback`;
|
||||
const scope = 'openid email';
|
||||
|
||||
const code_verifier: string = client.randomPKCECodeVerifier()
|
||||
const code_challenge: string =
|
||||
await client.calculatePKCECodeChallenge(code_verifier)
|
||||
let state: string;
|
||||
const parameters: Record<string, string> = {
|
||||
redirect_uri,
|
||||
scope,
|
||||
code_challenge,
|
||||
code_challenge_method: 'S256',
|
||||
}
|
||||
req.session.code_verifier = code_verifier;
|
||||
|
||||
if (!config.serverMetadata().supportsPKCE()) {
|
||||
/**
|
||||
* We cannot be sure the server supports PKCE so we're going to use state too.
|
||||
* Use of PKCE is backwards compatible even if the AS doesn't support it which
|
||||
* is why we're using it regardless. Like PKCE, random state must be generated
|
||||
* for every redirect to the authorization_endpoint.
|
||||
*/
|
||||
state = client.randomState()
|
||||
parameters.state = state
|
||||
req.session.state = state;
|
||||
}
|
||||
|
||||
const authUrl = client.buildAuthorizationUrl(config, parameters);
|
||||
return authUrl;
|
||||
}
|
||||
|
||||
async authorizeIdp(name: string, req: Request) {
|
||||
const code_verifier_session = req.session.code_verifier;
|
||||
const state_session = req.session.state;
|
||||
const url = new URL("http://localhost:3000" + req.url);
|
||||
|
||||
const idp = await lastValueFrom(
|
||||
this.identityProviderService.FindIdentityProvider({ name }),
|
||||
);
|
||||
|
||||
const config: client.Configuration = await client.discovery(
|
||||
new URL(idp.issueUrl),
|
||||
idp.clientId,
|
||||
idp.clientSecret,
|
||||
)
|
||||
|
||||
const tokens: client.TokenEndpointResponse = await client.authorizationCodeGrant(
|
||||
config,
|
||||
url,
|
||||
{
|
||||
pkceCodeVerifier: code_verifier_session,
|
||||
expectedState: state_session,
|
||||
},
|
||||
)
|
||||
|
||||
delete req.session.code_verifier;
|
||||
delete req.session.state;
|
||||
|
||||
console.log('Token Endpoint Response', tokens)
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
|
||||
export class CreatedIdentityProvider {
|
||||
|
||||
@ApiProperty()
|
||||
name: string;
|
||||
|
||||
@ApiProperty()
|
||||
clientId: string;
|
||||
|
||||
@ApiProperty()
|
||||
clientSecret: string;
|
||||
|
||||
@ApiProperty()
|
||||
issueUrl: string;
|
||||
}
|
||||
Reference in New Issue
Block a user