jwt issuing

This commit is contained in:
Evert Prants 2022-09-16 18:11:36 +03:00
parent 5769eca8ee
commit ff431c958c
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
11 changed files with 75 additions and 10 deletions

6
package-lock.json generated
View File

@ -2142,8 +2142,8 @@
"dev": true "dev": true
}, },
"node_modules/@icynet/oauth2-provider": { "node_modules/@icynet/oauth2-provider": {
"version": "1.0.0", "version": "1.0.5",
"resolved": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a", "resolved": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#20c0771bf08cafb27809e6cdb21dbff0ae40aec3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"express": "^4.17.3", "express": "^4.17.3",
@ -14155,7 +14155,7 @@
"dev": true "dev": true
}, },
"@icynet/oauth2-provider": { "@icynet/oauth2-provider": {
"version": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#a440d1f4ac53ccb6989dd25221797490611e240a", "version": "git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git#20c0771bf08cafb27809e6cdb21dbff0ae40aec3",
"from": "@icynet/oauth2-provider@git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git", "from": "@icynet/oauth2-provider@git+https://gitlab.icynet.eu/IcyNetwork/oauth2-provider.git",
"requires": { "requires": {
"express": "^4.17.3", "express": "^4.17.3",

View File

@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
import { Client } from 'connect-redis'; import { Client } from 'connect-redis';
import { User } from 'src/modules/objects/user/user.entity'; import { User } from 'src/modules/objects/user/user.entity';
const UNPRIVILEGED_STRIP = ['openid', 'id_token', 'management', 'implicit']; const UNPRIVILEGED_STRIP = ['id_token', 'management', 'implicit'];
@Injectable() @Injectable()
export class AdminService { export class AdminService {

View File

@ -39,8 +39,8 @@ export const configProviders: Provider<any>[] = [
}, },
jwt: { jwt: {
algorithm: 'RS256', algorithm: 'RS256',
issuer: 'localhost', issuer: 'http://localhost',
expiration: 3600, expiration: 604800,
}, },
database: { database: {
type: 'mysql', type: 'mysql',

View File

@ -56,6 +56,8 @@ export class ClientAdapter implements OAuth2ClientAdapter {
} }
checkScope(client: OAuth2Client, scope: string[]): boolean { checkScope(client: OAuth2Client, scope: string[]): boolean {
return scope.every((one) => client.scope.includes(one)); return scope.every(
(one) => one === 'profile' || client.scope.includes(one),
);
} }
} }

View File

@ -12,6 +12,7 @@ export class CodeAdapter implements OAuth2CodeAdapter {
clientId: string, clientId: string,
scope: string | string[], scope: string | string[],
ttl: number, ttl: number,
nonce?: string,
): Promise<string> { ): Promise<string> {
const client = await this._service.clientService.getById(clientId); const client = await this._service.clientService.getById(clientId);
const user = await this._service.userService.getById(userId); const user = await this._service.userService.getById(userId);
@ -31,6 +32,7 @@ export class CodeAdapter implements OAuth2CodeAdapter {
scopes, scopes,
expiresAt, expiresAt,
user, user,
nonce,
); );
return accessToken; return accessToken;

View File

@ -0,0 +1,43 @@
import { JWTAdapter, OAuth2User, OAuth2Client } from '@icynet/oauth2-provider';
import { OAuth2Service } from '../oauth2.service';
export class IcyJWTAdapter implements JWTAdapter {
constructor(private _client: OAuth2Service) {}
async issueIdToken(
rawUser: OAuth2User,
rawClient: OAuth2Client,
scope: string[],
nonce?: string,
): Promise<string> {
const user = await this._client.userService.getById(rawUser.id as number);
const userData: Record<string, unknown> = {
name: user.display_name,
preferred_username: user.username,
nickname: user.display_name,
updated_at: user.updated_at,
nonce,
};
if (scope.includes('email')) {
userData.email = user.email;
userData.email_verified = true;
}
if (
(scope.includes('image') || scope.includes('profile')) &&
user.picture
) {
userData.picture = `${this._client.config.get('app.base_url')}/uploads/${
user.picture.file
}`;
}
return this._client.jwt.issue(
userData,
user.uuid as string,
rawClient.id as string,
);
}
}

View File

@ -3,10 +3,17 @@ import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-cli
import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module'; import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module';
import { UploadModule } from 'src/modules/objects/upload/upload.module'; import { UploadModule } from 'src/modules/objects/upload/upload.module';
import { UserModule } from 'src/modules/objects/user/user.module'; import { UserModule } from 'src/modules/objects/user/user.module';
import { JWTModule } from '../jwt/jwt.module';
import { OAuth2Service } from './oauth2.service'; import { OAuth2Service } from './oauth2.service';
@Module({ @Module({
imports: [UserModule, UploadModule, OAuth2ClientModule, OAuth2TokenModule], imports: [
UserModule,
UploadModule,
OAuth2ClientModule,
OAuth2TokenModule,
JWTModule,
],
providers: [OAuth2Service], providers: [OAuth2Service],
exports: [OAuth2Service], exports: [OAuth2Service],
}) })

View File

@ -5,9 +5,11 @@ import { OAuth2ClientService } from 'src/modules/objects/oauth2-client/oauth2-cl
import { OAuth2TokenService } from 'src/modules/objects/oauth2-token/oauth2-token.service'; import { OAuth2TokenService } from 'src/modules/objects/oauth2-token/oauth2-token.service';
import { UserService } from 'src/modules/objects/user/user.service'; import { UserService } from 'src/modules/objects/user/user.service';
import { TokenService } from 'src/modules/utility/services/token.service'; import { TokenService } from 'src/modules/utility/services/token.service';
import { JWTService } from '../jwt/jwt.service';
import { AccessTokenAdapter } from './adapter/access-token.adapter'; import { AccessTokenAdapter } from './adapter/access-token.adapter';
import { ClientAdapter } from './adapter/client.adapter'; import { ClientAdapter } from './adapter/client.adapter';
import { CodeAdapter } from './adapter/code.adapter'; import { CodeAdapter } from './adapter/code.adapter';
import { IcyJWTAdapter } from './adapter/jwt.adapter';
import { RefreshTokenAdapter } from './adapter/refresh-token.adapter'; import { RefreshTokenAdapter } from './adapter/refresh-token.adapter';
import { UserAdapter } from './adapter/user.adapter'; import { UserAdapter } from './adapter/user.adapter';
@ -27,6 +29,7 @@ export class OAuth2Service {
user: new UserAdapter(this), user: new UserAdapter(this),
client: new ClientAdapter(this), client: new ClientAdapter(this),
code: new CodeAdapter(this), code: new CodeAdapter(this),
jwt: new IcyJWTAdapter(this),
}; };
public oauth = new OAuth2Provider( public oauth = new OAuth2Provider(
@ -64,6 +67,7 @@ export class OAuth2Service {
constructor( constructor(
public token: TokenService, public token: TokenService,
public jwt: JWTService,
public config: ConfigurationService, public config: ConfigurationService,
public userService: UserService, public userService: UserService,
public clientService: OAuth2ClientService, public clientService: OAuth2ClientService,

View File

@ -4,7 +4,6 @@ import {
Entity, Entity,
ManyToOne, ManyToOne,
OneToMany, OneToMany,
OneToOne,
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
UpdateDateColumn, UpdateDateColumn,
} from 'typeorm'; } from 'typeorm';

View File

@ -20,7 +20,13 @@ export class OAuth2ClientService {
'implicit', 'implicit',
]; ];
public availableScopes = ['image', 'email', 'privileges', 'management']; public availableScopes = [
'image',
'email',
'privileges',
'management',
'openid',
];
constructor( constructor(
@Inject('CLIENT_REPOSITORY') @Inject('CLIENT_REPOSITORY')

View File

@ -18,6 +18,7 @@ export class OAuth2TokenService {
scope: string, scope: string,
expiry: Date, expiry: Date,
user?: User, user?: User,
nonce?: string,
): Promise<OAuth2Token> { ): Promise<OAuth2Token> {
const newToken = new OAuth2Token(); const newToken = new OAuth2Token();
newToken.client = client; newToken.client = client;
@ -26,6 +27,7 @@ export class OAuth2TokenService {
newToken.scope = scope; newToken.scope = scope;
newToken.user = user; newToken.user = user;
newToken.expires_at = expiry; newToken.expires_at = expiry;
newToken.nonce = nonce;
await this.tokenRepository.save(newToken); await this.tokenRepository.save(newToken);