Skip to content

Commit

Permalink
Merge branch 'main' into 56-decode-token-even-if-it-is-expired
Browse files Browse the repository at this point in the history
Signed-off-by: prebbe <philip.rebbe@fau.de>
  • Loading branch information
prebbe committed Jun 22, 2022
2 parents b8367d9 + 58152cd commit e32b465
Show file tree
Hide file tree
Showing 33 changed files with 623 additions and 289 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CLIENT_CREDENTIALS_STRING=client_credentials
CLIENT_ID=
CLIENT_SECRET=
AUDIENCE=
AUDIENCE=oidc-app
ISSUER_STRING=
4 changes: 2 additions & 2 deletions .github/workflows/release-binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ jobs:
run: npm run bundle
- name: Generate Binary
run: npm run binary
- run: chmod -R +x index-*
- run: chmod -R +x openid-*
- name: Upload artifacts
uses: skx/github-action-publish-binaries@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: 'index-*'
args: 'openid-*'
Binary file added Documentation/BinaryUsage.pdf
Binary file not shown.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"bundle": "ncc build src/main.ts -o bundle",
"binary": "pkg bundle/index.js"
"binary": "pkg package.json"
},
"dependencies": {
"@nestjs/common": "^8.4.6",
Expand Down Expand Up @@ -82,7 +82,9 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node"
},
"bin": "bundle/index.js",
"pkg": {
"assets": ["views/**/*", "schema/**/*", "public/**/*", "logfiles/**/*", "node_modules/hbs/**/*.js"],
"targets": [ "node16-linux-x64", "node16-win-x64", "node16-macos-x64" ]
}
}
33 changes: 33 additions & 0 deletions settings/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"discovery": {
"parameter": [
"authorization_endpoint",
"claim_types_supported",
"claims_parameter_supported",
"claims_supported",
"code_challenge_methods_supported",
"device_authorization_endpoint",
"grant_types_supported",
"id_token_signing_alg_values_supported",
"issuer",
"jwks_uri",
"request_parameter_supported",
"request_uri_parameter_supported",
"require_request_uri_registration",
"response_modes_supported",
"response_types_supported",
"revocation_endpoint",
"revocation_endpoint_auth_methods_supported",
"scopes_supported",
"subject_types_supported",
"token_endpoint",
"token_endpoint_auth_methods_supported",
"userinfo_endpoint"
],
"validation_schema": "all.schema.json"
},
"token": {
"validation_schema": "test.schema.json",
"key_algorithm": "RS256"
}
}
6 changes: 4 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { AppController } from './app.controller';
import { ConfigModule } from '@nestjs/config';
import { TokenModule } from './token/token.module';
Expand All @@ -13,15 +12,18 @@ import { ProtocolModule } from './protocol/protocol.module';
import {ProtocolService} from "./protocol/protocol.service";
import {ProtocolController} from "./protocol/protocol.controller";
import {LoggerMiddleware} from "./utils/logger.middleware";
import { SettingsModule } from './settings/settings.module';
import { HelperModule } from './helper/helper.module';

@Module({
imports: [
ConfigModule.forRoot(),
UserModule,
DiscoveryModule,
TokenModule,
ProtocolModule,
FlowsModule,
SettingsModule,
HelperModule,
],
providers: [AppService, ProtocolService],
controllers: [AppController, ProtocolController],
Expand Down
99 changes: 23 additions & 76 deletions src/discovery/discovery.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { Express, Response } from 'express';
import { createReadStream, promises as fs } from 'fs';
import { join } from 'path';

import {DiscoveryService} from "./discovery.service";
import { DiscoveryService } from "./discovery.service";
import { DiscoveryDto } from "./discovery.dto";


@Controller('discovery')
Expand All @@ -27,76 +28,29 @@ export class DiscoveryController {

@Get('issuer')
@Render('index')
async discover_issuer(
@Query('issuer_url') issuer_url_s: string,
@Query('authorization_endpoint') authorization_endpoint_s: string,
@Query('claim_types_supported') claim_types_supported_s: string,
@Query('claims_parameter_supported') claims_parameter_supported_s: string,
@Query('claims_supported') claims_supported_s: string,
@Query('code_challenge_methods_supported')
code_challenge_methods_supported_s: string,
@Query('device_authorization_endpoint')
device_authorization_endpoint_s: string,
@Query('grant_types_supported') grant_types_supported_s: string,
@Query('id_token_signing_alg_values_supported')
id_token_signing_alg_values_supported_s: string,
@Query('issuer') issuer_s: string,
@Query('jwks_uri') jwks_uri_s: string,
@Query('request_parameter_supported') request_parameter_supported_s: string,
@Query('request_uri_parameter_supported')
request_uri_parameter_supported_s: string,
@Query('require_request_uri_registration')
require_request_uri_registration_s: string,
@Query('response_modes_supported') response_modes_supported_s: string,
@Query('response_types_supported') response_types_supported_s: string,
@Query('revocation_endpoint') revocation_endpoint_s: string,
@Query('revocation_endpoint_auth_methods_supported')
revocation_endpoint_auth_methods_supported_s: string,
@Query('scopes_supported') scopes_supported_s: string,
@Query('subject_types_supported') subject_types_supported_s: string,
@Query('token_endpoint') token_endpoint_s: string,
@Query('token_endpoint_auth_methods_supported')
token_endpoint_auth_methods_supported_s: string,
@Query('userinfo_endpoint') userinfo_endpoint_s: string,
@Query('schema') schema_s: string,
) {
const checkboxes = this.extracted(authorization_endpoint_s, claim_types_supported_s, claims_parameter_supported_s, claims_supported_s, code_challenge_methods_supported_s, device_authorization_endpoint_s, grant_types_supported_s, id_token_signing_alg_values_supported_s, issuer_s, jwks_uri_s, request_parameter_supported_s, request_uri_parameter_supported_s, require_request_uri_registration_s, response_modes_supported_s, response_types_supported_s, revocation_endpoint_s, revocation_endpoint_auth_methods_supported_s, scopes_supported_s, subject_types_supported_s, token_endpoint_s, token_endpoint_auth_methods_supported_s, userinfo_endpoint_s);
let keys = this.rememberSelectedParameters(checkboxes);
return await this.checkIssuerUrlDetails(schema_s, issuer_url_s, keys, checkboxes);
async discover_issuer() {
const schemas = await this.discoveryService.getSchemas(undefined);
const res = {
result: {
success: 1,
info: null,
previously_checked: this.discoveryService.getDefaultCheckboxes(),
},
short_message: 'Please input provider url',
schemas: schemas,
};
return res;
}

private extracted(authorization_endpoint_s: string, claim_types_supported_s: string, claims_parameter_supported_s: string, claims_supported_s: string, code_challenge_methods_supported_s: string, device_authorization_endpoint_s: string, grant_types_supported_s: string, id_token_signing_alg_values_supported_s: string, issuer_s: string, jwks_uri_s: string, request_parameter_supported_s: string, request_uri_parameter_supported_s: string, require_request_uri_registration_s: string, response_modes_supported_s: string, response_types_supported_s: string, revocation_endpoint_s: string, revocation_endpoint_auth_methods_supported_s: string, scopes_supported_s: string, subject_types_supported_s: string, token_endpoint_s: string, token_endpoint_auth_methods_supported_s: string, userinfo_endpoint_s: string) {
const checkboxes = {
authorization_endpoint: authorization_endpoint_s,
claim_types_supported: claim_types_supported_s,
claims_parameter_supported: claims_parameter_supported_s,
claims_supported: claims_supported_s,
code_challenge_methods_supported: code_challenge_methods_supported_s,
device_authorization_endpoint: device_authorization_endpoint_s,
grant_types_supported: grant_types_supported_s,
id_token_signing_alg_values_supported:
id_token_signing_alg_values_supported_s,
issuer: issuer_s,
jwks_uri: jwks_uri_s,
request_parameter_supported: request_parameter_supported_s,
request_uri_parameter_supported: request_uri_parameter_supported_s,
require_request_uri_registration: require_request_uri_registration_s,
response_modes_supported: response_modes_supported_s,
response_types_supported: response_types_supported_s,
revocation_endpoint: revocation_endpoint_s,
revocation_endpoint_auth_methods_supported:
revocation_endpoint_auth_methods_supported_s,
scopes_supported: scopes_supported_s,
subject_types_supported: subject_types_supported_s,
token_endpoint: token_endpoint_s,
token_endpoint_auth_methods_supported:
token_endpoint_auth_methods_supported_s,
userinfo_endpoint: userinfo_endpoint_s,
};
return checkboxes;
@Post('issuer')
@Render('index')
async discover_issuer_post(@Body() discoveryDto: DiscoveryDto) {
let keys = this.rememberSelectedParameters(discoveryDto);
const res = await this.checkIssuerUrlDetails(discoveryDto.schema, discoveryDto.issuer_url, keys, discoveryDto);
return res;
}

private rememberSelectedParameters(checkboxes) {
private rememberSelectedParameters(checkboxes: DiscoveryDto) {
let keys = [];
for (const key in checkboxes) {
if (checkboxes[key] === '1') {
Expand All @@ -106,15 +60,8 @@ export class DiscoveryController {
return keys;
}

private async checkIssuerUrlDetails(schema_s: string, issuer_url_s: string, keys: any[], checkboxes: { response_types_supported: string; request_parameter_supported: string; revocation_endpoint_auth_methods_supported: string; request_uri_parameter_supported: string; claims_parameter_supported: string; grant_types_supported: string; revocation_endpoint: string; scopes_supported: string; issuer: string; authorization_endpoint: string; userinfo_endpoint: string; device_authorization_endpoint: string; claims_supported: string; require_request_uri_registration: string; code_challenge_methods_supported: string; jwks_uri: string; subject_types_supported: string; claim_types_supported: string; id_token_signing_alg_values_supported: string; token_endpoint_auth_methods_supported: string; response_modes_supported: string; token_endpoint: string }) {
let empty_schemas;
if (schema_s === undefined) {
empty_schemas = [''];
} else {
empty_schemas = [schema_s, ''];
}
const uploaded_schemas = await fs.readdir('schema/discovery');
const schemas = empty_schemas.concat(uploaded_schemas.filter((x) => { return x !== schema_s; }));
private async checkIssuerUrlDetails(schema_s: string, issuer_url_s: string, keys: any[], checkboxes: DiscoveryDto) {
const schemas = await this.discoveryService.getSchemas(schema_s);
if (issuer_url_s === undefined) {
return {
result: {
Expand Down
26 changes: 26 additions & 0 deletions src/discovery/discovery.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export class DiscoveryDto {
schema: string;
issuer_url: string
authorization_endpoint_s: string;
claim_types_supported_s: string;
claims_parameter_supported_s: string;
claims_supported_s: string;
code_challenge_methods_supported_s: string;
device_authorization_endpoint_s: string;
grant_types_supported_s: string;
id_token_signing_alg_values_supported_s: string;
issuer_s: string;
jwks_uri_s: string;
request_parameter_supported_s: string;
request_uri_parameter_supported_s: string;
require_request_uri_registration_s: string;
response_modes_supported_s: string;
response_types_supported_s: string;
revocation_endpoint_s: string;
revocation_endpoint_auth_methods_supported_s: string;
scopes_supported_s: string;
subject_types_supported_s: string;
token_endpoint_s: string;
token_endpoint_auth_methods_supported_s: string;
userinfo_endpoint_s: string;
}
3 changes: 3 additions & 0 deletions src/discovery/discovery.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Module } from '@nestjs/common';
import { DiscoveryController } from './discovery.controller';
import { DiscoveryService } from './discovery.service';
import { SettingsModule } from '../settings/settings.module';
import { HelperModule } from '../helper/helper.module';

@Module({
imports: [SettingsModule, HelperModule],
controllers: [DiscoveryController],
providers: [DiscoveryService],
exports: [DiscoveryService],
Expand Down
3 changes: 3 additions & 0 deletions src/discovery/discovery.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DiscoveryService } from './discovery.service';
import { SettingsModule } from '../settings/settings.module';
import { HelperModule } from '../helper/helper.module';

describe('DiscoveryService', () => {
let service: DiscoveryService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [SettingsModule, HelperModule],
providers: [DiscoveryService],
}).compile();

Expand Down
70 changes: 21 additions & 49 deletions src/discovery/discovery.service.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,31 @@
import {HttpException, HttpStatus, Injectable} from '@nestjs/common';
import {Issuer} from "openid-client";
import Ajv, {JSONSchemaType} from "ajv"
import {HttpException, HttpStatus, Inject, Injectable} from '@nestjs/common';
import { join } from 'path';
import { SettingsService } from '../settings/settings.service';
import { HelperService } from '../helper/helper.service';

@Injectable()
export class DiscoveryService {
@Inject(SettingsService)
private readonly settingsService: SettingsService;
@Inject(HelperService)
private readonly helperService: HelperService;

async get_issuer(issuer_s) {
if(issuer_s === undefined || issuer_s === ''){
throw new HttpException(
'There was no issuer string passed to get the issuer',
HttpStatus.BAD_REQUEST,
);
}
const issuer = await Issuer.discover(issuer_s);
return issuer;
async getSchemas(schema_s: string) {
return this.helperService.getSchemasHelper(schema_s, 'discovery');
}
async validateJson(issuer: object, schema: object) {
const ajv = new Ajv();
const validate = ajv.compile(schema);
return [validate(issuer), validate.errors];
}

myStringify(issuer, required, keys) {
let res = '{\n';
let first = true;
for (const key in issuer) {
if (keys.includes(key)) {
if (!first) {
res = res + ',\n';
}
if (required.includes(key)) {
res = res + ` "${key}": ` + '<span style="color:green">' + JSON.stringify(issuer[key]) + '</span>';
} else {
res = res + ` "${key}": ` + JSON.stringify(issuer[key], null, 2);
}
first = false;
}
}
res = res + '\n}';
return res;
}
async get_issuer(issuer_s) { return this.helperService.get_issuer(issuer_s) }

async coloredFilteredValidationWithFileContent(issuer: object, schema: any, keys: any[]) {
const [ valid, errors ] = await this.validateJson(issuer, schema);
if (valid) {
const required = schema.required;
return [1, this.myStringify(issuer, required, keys)];
} else {
return [0, JSON.stringify(errors, null, 2)];
}
}
getDefaultCheckboxes() {
let x = {};
for (const i in this.settingsService.config.discovery.parameter) {
x[this.settingsService.config.discovery.parameter[i]] = 1;
}
return x;
}

async coloredFilteredValidation(issuer: object, schema_file: string, keys: any[]) {
const schema = require(join('..', '..', 'schema', schema_file));
return await this.coloredFilteredValidationWithFileContent(issuer, schema, keys);
}
async coloredFilteredValidation(issuer: object, schema_file: string, keys: any[]) {
const schema = require(join('..', '..', 'schema', schema_file));
return await this.helperService.coloredFilteredValidationWithFileContent(issuer, schema, keys);
}
}
12 changes: 12 additions & 0 deletions src/flows/Dto/clientCredentialFlowInput.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//SDPX-License-Identifier: MIT
//SDPX-FileCopyrightText: 2022 Philip Rebbe <rebbe.philip@fau.de>

export class ClientCredentialFlowInputDto {
issuerUrl: string;
clientId: string;
clientSecret: string;

constructor(partial: Partial<ClientCredentialFlowInputDto>) {
Object.assign(this, partial);
}
}
13 changes: 13 additions & 0 deletions src/flows/Dto/clientCredentialFlowResult.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//SDPX-License-Identifier: MIT
//SDPX-FileCopyrightText: 2022 Philip Rebbe <rebbe.philip@fau.de>

export class ClientCredentialFlowResultDto {
payload: string;
header: string;
success: boolean;
message: string;

constructor(partial: Partial<ClientCredentialFlowResultDto>) {
Object.assign(this, partial);
}
}
Loading

0 comments on commit e32b465

Please sign in to comment.