Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authorization: remove usage of anonymousReadAccess #4788

Merged
merged 7 commits into from
Dec 20, 2024
Merged
1 change: 1 addition & 0 deletions src/common/enums/authorization.credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum AuthorizationCredential {
GLOBAL_ADMIN = 'global-admin', // able to do everything, god mode
GLOBAL_SUPPORT = 'global-support', // able to manage platform level information, can per space have admin rights
GLOBAL_LICENSE_MANAGER = 'global-license-manager', // able to manage platform level information, can per space have admin rights
GLOBAL_ANONYMOUS = 'global-anonymous', // credential issued to all non-authenticated interactions
GLOBAL_REGISTERED = 'global-registered', // credential issued to all registered users
GLOBAL_COMMUNITY_READ = 'global-community-read', // able to view all details of the top level community
GLOBAL_SPACES_READER = 'global-spaces-read', // able to view all details of the top level community
Expand Down
4 changes: 2 additions & 2 deletions src/core/authentication.agent.info/agent.info.metadata.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ICredential } from '@domain/agent/credential';
import { ICredentialDefinition } from '@domain/agent/credential/credential.definition.interface';

export class AgentInfoMetadata {
userID!: string;
email!: string;
credentials: ICredential[] = [];
credentials: ICredentialDefinition[] = [];
communicationID!: string;
agentID!: string;
did!: string;
Expand Down
5 changes: 3 additions & 2 deletions src/core/authentication.agent.info/agent.info.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Module } from '@nestjs/common';
import { AgentInfoCacheService } from './agent.info.cache.service';
import { AgentInfoService } from './agent.info.service';
@Module({
imports: [],
providers: [AgentInfoCacheService],
exports: [AgentInfoCacheService],
providers: [AgentInfoService, AgentInfoCacheService],
exports: [AgentInfoService, AgentInfoCacheService],
})
export class AuthenticationAgentInfoModule {}
143 changes: 143 additions & 0 deletions src/core/authentication.agent.info/agent.info.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { ICredentialDefinition } from '@domain/agent/credential/credential.definition.interface';
import { AgentInfo } from './agent.info';
import { Inject, Injectable, LoggerService } from '@nestjs/common';
import { AuthorizationCredential, LogContext } from '@common/enums';
import { EntityNotInitializedException } from '@common/exceptions/entity.not.initialized.exception';
import { IVerifiedCredential } from '@domain/agent/verified-credential/verified.credential.interface';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';
import { User } from '@domain/community/user/user.entity';
import { AgentInfoMetadata } from './agent.info.metadata';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { EntityNotFoundException } from '@common/exceptions/entity.not.found.exception';
@Injectable()
export class AgentInfoService {
constructor(
@InjectEntityManager('default')
private entityManager: EntityManager,
@Inject(WINSTON_MODULE_NEST_PROVIDER)
private readonly logger: LoggerService
) {}

// Note for now a very empty service, but later as we start allowing "acting as" agents this service will expand.
// To consider: moving function related to AgentInfoMetaData from user service here, to remove dependency on UserModule in Authentication Module
public createAnonymousAgentInfo(): AgentInfo {
const emptyAgentInfo = new AgentInfo();
const anonymousCredential: ICredentialDefinition = {
type: AuthorizationCredential.GLOBAL_ANONYMOUS,
resourceID: '',
};
emptyAgentInfo.credentials = [anonymousCredential];
return emptyAgentInfo;
}

/**
* Retrieves the agent information metadata for a given email.
*
* @param email - The email address of the user whose agent information metadata is to be retrieved.
* @returns A promise that resolves to the agent information metadata if found, or undefined if the user is not registered.
* @throws Will log an error message if the user is not registered.
*/
public async getAgentInfoMetadata(
email: string
): Promise<AgentInfoMetadata | undefined> {
try {
const user = await this.entityManager.findOneOrFail(User, {
where: {
email: email,
},
relations: {
agent: {
credentials: true,
},
},
});
if (!user || !user.agent || !user.agent.credentials) {
throw new EntityNotFoundException(
`Unable to load User, Agent or Credentials for User: ${email}`,
LogContext.COMMUNITY
);
}
const userAgentInfoMetadata = new AgentInfoMetadata();
userAgentInfoMetadata.credentials = user.agent.credentials;
userAgentInfoMetadata.agentID = user.agent.id;
userAgentInfoMetadata.userID = user.id;
userAgentInfoMetadata.communicationID = user.communicationID;
return userAgentInfoMetadata;
} catch (error) {
this.logger.verbose?.(
`User not registered: ${email}, ${error}`,
LogContext.AUTH
);
return undefined;
}
}

/**
* Populates the given `agentInfo` object with metadata from `agentInfoMetadata`.
*
* @param agentInfo - The agent information object to be populated.
* @param agentInfoMetadata - The metadata containing information to populate the agent info.
*
* @remarks
* This method assigns the `agentID`, `userID`, and `communicationID` from `agentInfoMetadata` to `agentInfo`.
* If `agentInfoMetadata` contains credentials, they are also assigned to `agentInfo`.
* If credentials are not available, a warning is logged.
*/
public populateAgentInfoWithMetadata(
agentInfo: AgentInfo,
agentInfoMetadata: AgentInfoMetadata
): void {
agentInfo.agentID = agentInfoMetadata.agentID;
agentInfo.userID = agentInfoMetadata.userID;
agentInfo.communicationID = agentInfoMetadata.communicationID;

if (agentInfoMetadata.credentials) {
agentInfo.credentials = agentInfoMetadata.credentials;
} else {
this.logger.warn?.(
`Authentication Info: Unable to retrieve credentials for registered user: ${agentInfo.email}`,
LogContext.AUTH
);
}
}

public async buildAgentInfoForUser(userId: string): Promise<AgentInfo> {
const user = await this.entityManager.findOneOrFail(User, {
where: { id: userId },
relations: {
agent: {
credentials: true,
},
},
});

if (!user.agent || !user.agent.credentials) {
throw new EntityNotInitializedException(
`Agent not loaded for User: ${user.id}`,
LogContext.WHITEBOARD_INTEGRATION,
{ userId }
);
}

// const verifiedCredentials =
// await this.agentService.getVerifiedCredentials(user.agent);
const verifiedCredentials = [] as IVerifiedCredential[];
// construct the agent info object needed for isAccessGranted
let credentials: ICredentialDefinition[] = [];

if (credentials.length !== 0) {
credentials = user.agent.credentials.map(c => {
return {
type: c.type,
resourceID: c.resourceID,
};
});
}
techsmyth marked this conversation as resolved.
Show resolved Hide resolved

const agentInfo = new AgentInfo();
agentInfo.credentials = credentials;
agentInfo.verifiedCredentials = verifiedCredentials;
return agentInfo;
}
}
4 changes: 2 additions & 2 deletions src/core/authentication.agent.info/agent.info.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ICredential } from '@domain/agent/credential';
import { ICredentialDefinition } from '@domain/agent/credential/credential.definition.interface';
import { IVerifiedCredential } from '@domain/agent/verified-credential/verified.credential.interface';
export class AgentInfo {
userID = '';
email = '';
emailVerified = false;
firstName = '';
lastName = '';
credentials: ICredential[] = [];
credentials: ICredentialDefinition[] = [];
verifiedCredentials: IVerifiedCredential[] = [];
communicationID = '';
agentID = '';
Expand Down
8 changes: 2 additions & 6 deletions src/core/authentication/authentication.module.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from '@domain/community/user/user.module';
import { AuthenticationService } from './authentication.service';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { OryStrategy } from './ory.strategy';
import { CredentialModule } from '@domain/agent/credential/credential.module';
import { OryApiStrategy } from './ory.api.strategy';
import { AgentModule } from '@domain/agent/agent/agent.module';
import { AuthenticationAgentInfoModule } from '@core/authentication.agent.info/agent.info.module';
import { KratosModule } from '@services/infrastructure/kratos/kratos.module';
import { AgentModule } from '@domain/agent/agent/agent.module';
@Module({
imports: [
PassportModule.register({
session: false,
defaultStrategy: 'oathkeeper-jwt',
}),
UserModule,
AgentModule,
CredentialModule,
AuthenticationAgentInfoModule,
KratosModule,
AgentModule,
CacheModule.register(),
JwtModule.registerAsync({
imports: [ConfigModule],
Expand Down
Loading