openid-configuration
This commit is contained in:
parent
5a40b44dd1
commit
e394880539
@ -1,10 +1,46 @@
|
|||||||
import { Controller, Get, Redirect } from '@nestjs/common';
|
import { Controller, Get, Redirect } from '@nestjs/common';
|
||||||
|
import { ConfigurationService } from './modules/config/config.service';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
|
constructor(private config: ConfigurationService) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@Redirect('/account/general')
|
@Redirect('/account/general')
|
||||||
getHello() {
|
getHello() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('/.well-known/openid-configuration')
|
||||||
|
openidConfiguration() {
|
||||||
|
const base = this.config.get<string>('app.base_url');
|
||||||
|
return {
|
||||||
|
issuer: this.config.get('jwt.issuer'),
|
||||||
|
authorization_endpoint: `${base}/oauth2/authorize`,
|
||||||
|
token_endpoint: `${base}/oauth2/token`,
|
||||||
|
jwks_uri: `${base}/oauth2/jwks`,
|
||||||
|
userinfo_endpoint: `${base}/api/user`,
|
||||||
|
introspection_endpoint: `${base}/oauth2/introspect`,
|
||||||
|
response_types_supported: ['code', 'id_token'],
|
||||||
|
id_token_signing_alg_values_supported: [this.config.get('jwt.algorithm')],
|
||||||
|
subject_types_supported: ['public'],
|
||||||
|
scopes_supported: ['openid', 'profile', 'email'],
|
||||||
|
claims_supported: [
|
||||||
|
'aud',
|
||||||
|
'exp',
|
||||||
|
'iat',
|
||||||
|
'iss',
|
||||||
|
'sub',
|
||||||
|
'name',
|
||||||
|
'preferred_username',
|
||||||
|
'profile',
|
||||||
|
'picture',
|
||||||
|
'updated_at',
|
||||||
|
'email',
|
||||||
|
'email_verified',
|
||||||
|
],
|
||||||
|
code_challenge_methods_supported: ['plain', 'S256'],
|
||||||
|
grant_types_supported: ['authorization_code', 'refresh_token'],
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,12 @@ export const jwtProviders = [
|
|||||||
useFactory: async (path: string) => readFile(join(path, 'jwt.public.pem')),
|
useFactory: async (path: string) => readFile(join(path, 'jwt.public.pem')),
|
||||||
inject: ['PRIVATE_PATH'],
|
inject: ['PRIVATE_PATH'],
|
||||||
} as FactoryProvider<Buffer>,
|
} as FactoryProvider<Buffer>,
|
||||||
|
{
|
||||||
|
provide: 'JWT_JWKS',
|
||||||
|
useFactory: async (path: string) =>
|
||||||
|
JSON.parse(
|
||||||
|
await readFile(join(path, 'jwks.json'), { encoding: 'utf-8' }),
|
||||||
|
),
|
||||||
|
inject: ['PRIVATE_PATH'],
|
||||||
|
} as FactoryProvider<Record<string, unknown>>,
|
||||||
];
|
];
|
||||||
|
@ -12,6 +12,7 @@ export class JWTService {
|
|||||||
constructor(
|
constructor(
|
||||||
@Inject('JWT_PRIVATE_KEY') private _privateKey: Buffer,
|
@Inject('JWT_PRIVATE_KEY') private _privateKey: Buffer,
|
||||||
@Inject('JWT_PUBLIC_KEY') private _publicKey: Buffer,
|
@Inject('JWT_PUBLIC_KEY') private _publicKey: Buffer,
|
||||||
|
@Inject('JWT_JWKS') private _jwks: Record<string, unknown>,
|
||||||
private _config: ConfigurationService,
|
private _config: ConfigurationService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -41,4 +42,13 @@ export class JWTService {
|
|||||||
audience,
|
audience,
|
||||||
}) as jwt.JwtPayload;
|
}) as jwt.JwtPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: generate on-the-go
|
||||||
|
public get jwks() {
|
||||||
|
return {
|
||||||
|
alg: this._config.get('jwt.algorithm'),
|
||||||
|
...this._jwks,
|
||||||
|
use: 'sig',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,9 @@ export class IcyJWTAdapter implements JWTAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(scope.includes('image') || scope.includes('profile')) &&
|
(scope.includes('image') ||
|
||||||
|
scope.includes('picture') ||
|
||||||
|
scope.includes('profile')) &&
|
||||||
user.picture
|
user.picture
|
||||||
) {
|
) {
|
||||||
userData.picture = `${this._client.config.get('app.base_url')}/uploads/${
|
userData.picture = `${this._client.config.get('app.base_url')}/uploads/${
|
||||||
|
@ -15,6 +15,6 @@ import { OAuth2Service } from './oauth2.service';
|
|||||||
JWTModule,
|
JWTModule,
|
||||||
],
|
],
|
||||||
providers: [OAuth2Service],
|
providers: [OAuth2Service],
|
||||||
exports: [OAuth2Service],
|
exports: [OAuth2Service, JWTModule],
|
||||||
})
|
})
|
||||||
export class OAuth2Module {}
|
export class OAuth2Module {}
|
||||||
|
@ -40,7 +40,10 @@ export class OAuth2Service {
|
|||||||
let disallowedScopes = [...ALWAYS_UNAVAILABLE];
|
let disallowedScopes = [...ALWAYS_UNAVAILABLE];
|
||||||
|
|
||||||
Object.keys(SCOPE_DESCRIPTION).forEach((item) => {
|
Object.keys(SCOPE_DESCRIPTION).forEach((item) => {
|
||||||
if (scope.includes(item)) {
|
if (
|
||||||
|
scope.includes(item) ||
|
||||||
|
(item === 'image' && scope.includes('picture'))
|
||||||
|
) {
|
||||||
allowedScopes.push(SCOPE_DESCRIPTION[item]);
|
allowedScopes.push(SCOPE_DESCRIPTION[item]);
|
||||||
} else {
|
} else {
|
||||||
disallowedScopes.push(SCOPE_DESCRIPTION[item]);
|
disallowedScopes.push(SCOPE_DESCRIPTION[item]);
|
||||||
|
@ -22,6 +22,8 @@ export class OAuth2ClientService {
|
|||||||
|
|
||||||
public availableScopes = [
|
public availableScopes = [
|
||||||
'image',
|
'image',
|
||||||
|
'picture',
|
||||||
|
'profile',
|
||||||
'email',
|
'email',
|
||||||
'privileges',
|
'privileges',
|
||||||
'management',
|
'management',
|
||||||
|
@ -14,6 +14,7 @@ import { Scope } from 'src/decorators/scope.decorator';
|
|||||||
import { CurrentUser } from 'src/decorators/user.decorator';
|
import { CurrentUser } from 'src/decorators/user.decorator';
|
||||||
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
import { ConfigurationService } from 'src/modules/config/config.service';
|
import { ConfigurationService } from 'src/modules/config/config.service';
|
||||||
|
import { JWTService } from 'src/modules/jwt/jwt.service';
|
||||||
import { User } from 'src/modules/objects/user/user.entity';
|
import { User } from 'src/modules/objects/user/user.entity';
|
||||||
import { OAuth2Service } from '../../oauth2/oauth2.service';
|
import { OAuth2Service } from '../../oauth2/oauth2.service';
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ export class OAuth2Controller {
|
|||||||
constructor(
|
constructor(
|
||||||
private _service: OAuth2Service,
|
private _service: OAuth2Service,
|
||||||
private _config: ConfigurationService,
|
private _config: ConfigurationService,
|
||||||
|
private _jwt: JWTService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// These requests are just passed straight on to the provider controller
|
// These requests are just passed straight on to the provider controller
|
||||||
@ -96,7 +98,9 @@ export class OAuth2Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(scope.includes('image') || scope.includes('user:image')) &&
|
(scope.includes('image') ||
|
||||||
|
scope.includes('picture') ||
|
||||||
|
scope.includes('user:image')) &&
|
||||||
user.picture
|
user.picture
|
||||||
) {
|
) {
|
||||||
userData.image = `${this._config.get('app.base_url')}/uploads/${
|
userData.image = `${this._config.get('app.base_url')}/uploads/${
|
||||||
@ -114,4 +118,11 @@ export class OAuth2Controller {
|
|||||||
|
|
||||||
return userData;
|
return userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('jwks')
|
||||||
|
getJWKS() {
|
||||||
|
return {
|
||||||
|
keys: [this._jwt.jwks],
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user