mirror of
https://github.com/dadosfera/maestro.git
synced 2026-08-31 19:58:21 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
193031dfdd | ||
|
|
f626a9bb5e | ||
|
|
2c908d8d95 | ||
|
|
da35633d42 | ||
|
|
cc7e06013f |
@@ -625,6 +625,7 @@ export const DADOSFERA_MODULES_KEYS = {
|
||||
DANGER_ZONE: 'danger-zone',
|
||||
PII: 'pii',
|
||||
EMBED: 'embedded-analytics',
|
||||
EMBED_ASSIGNED: 'embed-assigned',
|
||||
}
|
||||
|
||||
export const DADOSFERA_MODULES: Array<DadosferaModule> = [
|
||||
|
||||
@@ -15,7 +15,7 @@ export class AssignController {
|
||||
@RequireSomePermission(
|
||||
PERMISSIONS_GROUPS.USERS.permissions.ADMIN
|
||||
)
|
||||
@RequireModule(DADOSFERA_MODULES_KEYS.EMBED)
|
||||
@RequireModule(DADOSFERA_MODULES_KEYS.EMBED_ASSIGNED)
|
||||
create(@Body() createAssignDto: CreateAssignDto, @User() user: RequestUser) {
|
||||
const metadata = PackTheMetadata(user);
|
||||
return this.assignService.create(createAssignDto, metadata);
|
||||
@@ -25,7 +25,7 @@ export class AssignController {
|
||||
@RequireSomePermission(
|
||||
PERMISSIONS_GROUPS.USERS.permissions.ADMIN
|
||||
)
|
||||
@RequireModule(DADOSFERA_MODULES_KEYS.EMBED)
|
||||
@RequireModule(DADOSFERA_MODULES_KEYS.EMBED_ASSIGNED)
|
||||
async get(@User() user: RequestUser) {
|
||||
const metadata = PackTheMetadata(user);
|
||||
return await this.assignService.get(metadata);
|
||||
|
||||
@@ -153,12 +153,27 @@ export class IdentityProviderController {
|
||||
throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_RESPONSE);
|
||||
}
|
||||
|
||||
const origin = req.headers['origin'] as string;
|
||||
try {
|
||||
const origin = req.headers['origin'] as string;
|
||||
this.logger.info('Header Origin: ' + origin);
|
||||
|
||||
const lang = language.substring(0, 2) + language.substring(2).toUpperCase();
|
||||
const callbackUrl = process.env.ENV !== "prd" ? `${origin}/auth/callback` : `${origin}/${lang}/auth/callback`;
|
||||
const lang =
|
||||
language.substring(0, 2) + language.substring(2).toUpperCase();
|
||||
const callbackUrl =
|
||||
process.env.ENV !== 'prd'
|
||||
? `${origin}/auth/callback`
|
||||
: `${origin}/${lang}/auth/callback`;
|
||||
|
||||
return await this.identityProviderService.getTokenByIdp(code, state, callbackUrl);
|
||||
this.logger.info('Callback URL: ' + callbackUrl);
|
||||
return await this.identityProviderService.getTokenByIdp(
|
||||
code,
|
||||
state,
|
||||
callbackUrl,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@Get('/links')
|
||||
@@ -166,41 +181,66 @@ export class IdentityProviderController {
|
||||
async providerLinks(@Req() req: Request) {
|
||||
this.logger.info('GET /identity-providers/links');
|
||||
|
||||
const frontDomain = req.headers['origin'] as string;
|
||||
try {
|
||||
const frontDomain = req.headers['origin'] as string;
|
||||
this.logger.info('Header Origin: ' + frontDomain);
|
||||
|
||||
if (!frontDomain) {
|
||||
throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_HEADER);
|
||||
if (!frontDomain) {
|
||||
this.logger.info('Not found front domain');
|
||||
throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_HEADER);
|
||||
}
|
||||
|
||||
const result =
|
||||
await this.identityProviderService.identityProvidersLinksPerDomain(
|
||||
frontDomain,
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const result =
|
||||
await this.identityProviderService.identityProvidersLinksPerDomain(
|
||||
frontDomain,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Redirect()
|
||||
async loginIdp(@Param('id') id: string, @Req() req: Request, @Language() language: LanguageEnum) {
|
||||
async loginIdp(
|
||||
@Param('id') id: string,
|
||||
@Req() req: Request,
|
||||
@Language() language: LanguageEnum,
|
||||
) {
|
||||
this.logger.info('GET /identity-providers/:id');
|
||||
|
||||
try {
|
||||
const frontDomain =
|
||||
(req.headers['origin'] as string) || (req.headers['referer'] as string);
|
||||
this.logger.info(`Front domain: ${frontDomain}`);
|
||||
const host =
|
||||
frontDomain.lastIndexOf('/') !== -1
|
||||
? frontDomain.substring(0, frontDomain.lastIndexOf('/'))
|
||||
: frontDomain;
|
||||
|
||||
const frontDomain = req.headers['origin'] as string || req.headers['referer'] as string;
|
||||
this.logger.info(`Front domain: ${frontDomain}`);
|
||||
const host = frontDomain.lastIndexOf('/') !== -1
|
||||
? frontDomain.substring(0, frontDomain.lastIndexOf('/'))
|
||||
: frontDomain;
|
||||
const lang =
|
||||
language.substring(0, 2) + language.substring(2).toUpperCase();
|
||||
const callbackUrl =
|
||||
process.env.ENV !== 'prd'
|
||||
? `${host}/auth/callback`
|
||||
: `${host}/${lang}/auth/callback`;
|
||||
|
||||
const lang = language.substring(0, 2) + language.substring(2).toUpperCase();
|
||||
const callbackUrl = process.env.ENV !== "prd" ? `${host}/auth/callback` : `${host}/${lang}/auth/callback`;
|
||||
this.logger.info('Callback URL: ' + callbackUrl);
|
||||
const redirectUrl =
|
||||
await this.identityProviderService.loginIdentityProvider(
|
||||
id,
|
||||
callbackUrl,
|
||||
);
|
||||
|
||||
const redirectUrl =
|
||||
await this.identityProviderService.loginIdentityProvider(id, callbackUrl);
|
||||
|
||||
this.logger.info(`Redirecting to: ${redirectUrl}`);
|
||||
return {
|
||||
url: redirectUrl,
|
||||
};
|
||||
this.logger.info(`Redirecting to: ${redirectUrl}`);
|
||||
return {
|
||||
url: redirectUrl,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,21 @@ import { Metadata } from '@grpc/grpc-js';
|
||||
import { Issuer, generators } from 'openid-client';
|
||||
import { SsoSignInDto } from './dto/sso-signin.dto';
|
||||
import { CacheService } from 'src/services/cache.service';
|
||||
import { Request } from 'express';
|
||||
import { CreateIdentityProvider } from './dto/identity-provider.dto';
|
||||
import DadosferaLogger from '@dadosfera/dadosfera-logs';
|
||||
|
||||
@Injectable()
|
||||
export class IdentityProviderService implements OnModuleInit {
|
||||
private logger: DadosferaLogger;
|
||||
private identityProviderService: IdentityProviderProtoService;
|
||||
constructor(
|
||||
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
|
||||
private readonly cacheService: CacheService<SsoSignInDto>,
|
||||
) {}
|
||||
@Inject(DadosferaLogger)
|
||||
private dadosferaLoggger: DadosferaLogger
|
||||
) {
|
||||
this.logger = dadosferaLoggger.logger;
|
||||
}
|
||||
|
||||
onModuleInit() {
|
||||
this.identityProviderService =
|
||||
@@ -33,22 +38,26 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
}
|
||||
|
||||
async create(body: IdentityProviderRequest, metadata: Metadata) {
|
||||
this.logger.info("Call IdentityProvider GRPC Create")
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.Create(body, metadata),
|
||||
);
|
||||
}
|
||||
|
||||
async getList(metadata: Metadata) {
|
||||
this.logger.info("Call IdentityProvider GRPC GetList")
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.GetList({}, metadata),
|
||||
);
|
||||
}
|
||||
|
||||
async loginIdentityProvider(id: string, callbackUrl: string) {
|
||||
this.logger.info("Call IdentityProvider GRPC FindIdentityProvider with: " + id);
|
||||
const idp = await lastValueFrom(
|
||||
this.identityProviderService.FindIdentityProvider({ id }),
|
||||
);
|
||||
|
||||
this.logger.info("Discovery issueURL: " + idp.issuerUrl)
|
||||
const issuer = await Issuer.discover(idp.issuerUrl);
|
||||
const client = new issuer.Client({
|
||||
client_id: idp.clientId,
|
||||
@@ -57,14 +66,19 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
response_types: ['code'],
|
||||
});
|
||||
|
||||
this.logger.info("Generate Challenge")
|
||||
const code_verifier: string = generators.codeVerifier();
|
||||
const code_challenge: string = generators.codeChallenge(code_verifier);
|
||||
|
||||
this.logger.info("Generate State")
|
||||
const state = generators.state();
|
||||
|
||||
this.logger.info("Generate Nonce")
|
||||
const nonce = generators.nonce();
|
||||
|
||||
// Using state because it is returned in the callback
|
||||
// and we can use it to retrieve the code_verifier and nonce
|
||||
this.logger.info("Save Login parameters in redis")
|
||||
await this.cacheService.set(state, {
|
||||
codeVerifier: code_verifier,
|
||||
nonce,
|
||||
@@ -76,6 +90,7 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
redirectUrls: idp.redirectUrls,
|
||||
});
|
||||
|
||||
this.logger.info("Generate Authorization URL")
|
||||
const url = client.authorizationUrl({
|
||||
scope: 'openid email',
|
||||
response_type: 'code',
|
||||
@@ -86,16 +101,20 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
redirect_uri: callbackUrl,
|
||||
});
|
||||
const idpUrl = url + '&identity_provider=' + idp.name;
|
||||
this.logger.info(idpUrl)
|
||||
return idpUrl;
|
||||
}
|
||||
|
||||
async getTokenByIdp(code: string, state: string, callbackUrl: string) {
|
||||
this.logger.info("Get login parameters in redis")
|
||||
const ssoSign = await this.cacheService.get(state);
|
||||
|
||||
if (!ssoSign) {
|
||||
this.logger.info("Login Parameters Not Found")
|
||||
throw new BadRequestException('SSO sign-in is expired or not found');
|
||||
}
|
||||
|
||||
this.logger.info("Discovery Issue URL: " + ssoSign.issuerUrl)
|
||||
const issuer = await Issuer.discover(ssoSign.issuerUrl);
|
||||
const client = new issuer.Client({
|
||||
client_id: ssoSign.clientId,
|
||||
@@ -103,22 +122,22 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
redirect_uris: ssoSign.redirectUrls,
|
||||
});
|
||||
|
||||
if (ssoSign === null) {
|
||||
throw new BadRequestException('SSO sign-in is expired or not found');
|
||||
}
|
||||
|
||||
const params = client.callbackParams(
|
||||
`${callbackUrl}?code=${code}&state=${state}`,
|
||||
);
|
||||
try {
|
||||
|
||||
this.logger.info("Get Token Set");
|
||||
const tokenSet = await client.callback(callbackUrl, params, {
|
||||
nonce: ssoSign.nonce,
|
||||
code_verifier: ssoSign.codeVerifier,
|
||||
state: ssoSign.state
|
||||
});
|
||||
|
||||
this.logger.info("Delete parameters in redis");
|
||||
await this.cacheService.delete(ssoSign.state);
|
||||
|
||||
this.logger.info("Call IdentityProvider GRPC SignInUser");
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.SignInUser({
|
||||
accessToken: tokenSet.access_token,
|
||||
@@ -128,12 +147,13 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this.logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteIdentityProvider(id: string, metadata: Metadata) {
|
||||
this.logger.info("Call IdentityProvider GRPC Delete with: " + id)
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.DeleteIdentityProvider({ id }, metadata),
|
||||
);
|
||||
@@ -144,6 +164,7 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
body: CreateIdentityProvider,
|
||||
metadata: Metadata,
|
||||
) {
|
||||
this.logger.info("Call IdentityProvider GRPC Update with: " + id)
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.UpdateIdentityProvider(
|
||||
{
|
||||
@@ -156,6 +177,7 @@ export class IdentityProviderService implements OnModuleInit {
|
||||
}
|
||||
|
||||
async identityProvidersLinksPerDomain(frontDomain: string) {
|
||||
this.logger.info("Call IdentityProvider GRPC LinksPerDomain with: " + frontDomain)
|
||||
return await lastValueFrom(
|
||||
this.identityProviderService.GetProviderLinksFromDomain({ frontDomain }),
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { redisStore } from 'cache-manager-ioredis-yet';
|
||||
CacheModule.registerAsync({
|
||||
useFactory: async () => ({
|
||||
store: await redisStore({
|
||||
ttl: 1000 * 60, //1 minute
|
||||
ttl: 5 * 1000 * 60, // 5 minute
|
||||
host: process.env.REDIS_HOST,
|
||||
port: process.env.REDIS_PORT && Number(process.env.REDIS_PORT),
|
||||
db: process.env.REDIS_DATABASE && Number(process.env.REDIS_DATABASE),
|
||||
|
||||
Reference in New Issue
Block a user