Skip to content

Instantly share code, notes, and snippets.

@andreacioni
Last active February 4, 2025 14:27
Show Gist options
  • Select an option

  • Save andreacioni/eb5bad0bcca18cf4fb732c6d7e29e3e8 to your computer and use it in GitHub Desktop.

Select an option

Save andreacioni/eb5bad0bcca18cf4fb732c6d7e29e3e8 to your computer and use it in GitHub Desktop.

Revisions

  1. andreacioni revised this gist Sep 13, 2022. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions app.controller-4.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    @Controller()
    export class AppController {
    constructor(
    private readonly authService: AuthService,
    private readonly userService: UserService,
    private readonly samlStrategy: SamlStrategy, //new dependency needed here
    ) {}

    // [...]

    @Get('api/auth/sso/saml/metadata')
    async getSpMetadata(@Response() res: express.Response) {
    const ret = this.samlStrategy.generateServiceProviderMetadata(null, null);
    res.type('application/xml');
    res.send(ret);
    }

    }


  2. andreacioni revised this gist Sep 13, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ export class SamlStrategy extends PassportStrategy(Strategy) {
    constructor() {
    super({
    issuer: 'saml2-nest-poc',
    path: 'api/auth/sso/saml/ac',
    callbackUrl: 'http://localhost:3000/api/auth/sso/saml/ac',
    cert: 'MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==',
    entryPoint: 'https://samltest.id/idp/profile/SAML2/Redirect/SSO',
    wantAssertionsSigned: true,
  3. andreacioni revised this gist Sep 11, 2022. 1 changed file with 19 additions and 0 deletions.
    19 changes: 19 additions & 0 deletions user.service.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    import { Injectable } from '@nestjs/common';
    import { User } from '../model/user';

    @Injectable()
    export class UserService {
    private _store: Map<string, User>;

    constructor() {
    this._store = new Map<string, User>();
    }

    storeUser(user: User): void {
    this._store.set(user.username, user);
    }

    retrieveUser(id: string): User | undefined {
    return this._store.get(id);
    }
    }
  4. andreacioni revised this gist Sep 11, 2022. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions auth.service.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    import { Injectable } from '@nestjs/common';
    import { JwtService } from '@nestjs/jwt';
    import { User } from '../model/user';

    @Injectable()
    export class AuthService {
    constructor(private jwtService: JwtService) {}

    getTokenForUser(user: User) {
    const payload = {
    sub: user.username,
    iss: user.issuer,
    };
    return this.jwtService.sign(payload);
    }
    }
  5. andreacioni revised this gist Sep 11, 2022. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -19,6 +19,7 @@
    if(params.has("jwt")) {
    jwt = params.get("jwt");
    localStorage.setItem('jwt', jwt);
    window.location.href = '/'
    } else {
    jwt = localStorage.getItem('jwt')
    }
    @@ -39,6 +40,8 @@

    goToProfilePage()
    document.getElementById("userid").innerHTML = json.username;
    document.getElementById("phone").innerHTML = json.phone;
    document.getElementById("email").innerHTML = json.email;
    }
    }

    @@ -55,6 +58,10 @@
    </div>
    <div style="display: none;" id="user-profile-div">
    <p>Hello <span id="userid"></span>!</p>
    <ul>
    <li>Email: <span id="email"></span></li>
    <li>Phone: <span id="phone"></span></li>
    </ul>
    <p><a id="logout" href="#" onclick="logout()">Log Out</a></p>
    </div>

  6. andreacioni revised this gist Sep 11, 2022. 1 changed file with 27 additions and 0 deletions.
    27 changes: 27 additions & 0 deletions jwt.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    import { ExtractJwt, Strategy } from 'passport-jwt';
    import { PassportStrategy } from '@nestjs/passport';
    import { ForbiddenException, Injectable } from '@nestjs/common';
    import { jwtConstants } from './constants';
    import { UserService } from 'src/user/user.service';
    import { User } from '../model/user';

    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(private readonly userService: UserService) {
    super({
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    ignoreExpiration: false,
    secretOrKey: jwtConstants.secret,
    });
    }

    async validate(payload: any) {
    const user: User | undefined = this.userService.retrieveUser(payload.sub);

    if (user) {
    return user;
    }

    throw new ForbiddenException('user was not found');
    }
    }
  7. andreacioni revised this gist Sep 11, 2022. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions jwt-auth.guard.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    import { Injectable } from '@nestjs/common';
    import { AuthGuard } from '@nestjs/passport';

    @Injectable()
    export class JwtAuthGuard extends AuthGuard('jwt') {}
  8. andreacioni revised this gist Sep 11, 2022. 2 changed files with 3 additions and 17 deletions.
    5 changes: 3 additions & 2 deletions app.controller-2.ts
    Original file line number Diff line number Diff line change
    @@ -6,8 +6,9 @@
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const jwt = this.authService.getTokenForUser(req.user as User);
    this.userService.storeUser(req.user as User);
    const user = req.user as User;
    const jwt = this.authService.getTokenForUser(user);
    this.userService.storeUser(user);
    this, res.redirect('/?jwt=' + jwt);
    }
    }
    15 changes: 0 additions & 15 deletions app.controller-3.ts
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,3 @@
    @Post('api/auth/sso/saml/ac')
    @UseGuards(SamlAuthGuard)
    async samlAssertionConsumer(
    @Request() req: express.Request,
    @Response() res: express.Response,
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const user = req.user as User;
    const jwt = this.authService.getTokenForUser(user);
    this.userService.storeUser(user);
    this, res.redirect('/?jwt=' + jwt);
    }
    }

    @UseGuards(JwtAuthGuard)
    @Get('api/profile')
    getProfile(@Request() req: any) {
  9. andreacioni revised this gist Sep 11, 2022. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions app.controller-3.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    @Post('api/auth/sso/saml/ac')
    @UseGuards(SamlAuthGuard)
    async samlAssertionConsumer(
    @Request() req: express.Request,
    @Response() res: express.Response,
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const user = req.user as User;
    const jwt = this.authService.getTokenForUser(user);
    this.userService.storeUser(user);
    this, res.redirect('/?jwt=' + jwt);
    }
    }

    @UseGuards(JwtAuthGuard)
    @Get('api/profile')
    getProfile(@Request() req: any) {
    return req.user;
    }
  10. andreacioni revised this gist Sep 11, 2022. 1 changed file with 17 additions and 3 deletions.
    20 changes: 17 additions & 3 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable } from '@nestjs/common';
    import { Strategy } from 'passport-saml';
    import { ForbiddenException, Injectable } from '@nestjs/common';
    import { Strategy, Profile } from 'passport-saml';
    import { User } from '../model/user';

    @Injectable()
    @@ -14,4 +14,18 @@ export class SamlStrategy extends PassportStrategy(Strategy) {
    wantAssertionsSigned: true,
    });
    }
    }

    async validate(profile: Profile) {
    try {
    const user: User = {
    username: profile['urn:oid:0.9.2342.19200300.100.1.1'] as string,
    email: profile.mail as string,
    issuer: profile.issuer as string,
    phone: profile['urn:oid:2.5.4.20'] as string,
    };
    return user;
    } catch (e) {
    throw new ForbiddenException('invalid user attributes');
    }
    }
    }
  11. andreacioni revised this gist Sep 11, 2022. 1 changed file with 0 additions and 11 deletions.
    11 changes: 0 additions & 11 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -14,15 +14,4 @@ export class SamlStrategy extends PassportStrategy(Strategy) {
    wantAssertionsSigned: true,
    });
    }

    async validate(profile: any) {
    const user: User = {
    username: profile['urn:oid:0.9.2342.19200300.100.1.1'],
    email: profile.mail,
    issuer: profile.issuer,
    phone: profile['urn:oid:2.5.4.20'],
    };

    return user;
    }
    }
  12. andreacioni revised this gist Sep 11, 2022. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -17,11 +17,12 @@ export class SamlStrategy extends PassportStrategy(Strategy) {

    async validate(profile: any) {
    const user: User = {
    username: profile.nameID,
    role: profile.Role,
    username: profile['urn:oid:0.9.2342.19200300.100.1.1'],
    email: profile.mail,
    issuer: profile.issuer,
    phone: profile['urn:oid:2.5.4.20'],
    };

    return user;
    }
    }
    }
  13. andreacioni revised this gist Sep 10, 2022. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,6 @@ export class SamlStrategy extends PassportStrategy(Strategy) {
    cert: 'MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==',
    entryPoint: 'https://samltest.id/idp/profile/SAML2/Redirect/SSO',
    wantAssertionsSigned: true,
    disableRequestedAuthnContext: true,
    });
    }

  14. andreacioni revised this gist Sep 10, 2022. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -11,11 +11,8 @@ export class SamlStrategy extends PassportStrategy(Strategy) {
    path: 'api/auth/sso/saml/ac',
    cert: 'MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==',
    entryPoint: 'https://samltest.id/idp/profile/SAML2/Redirect/SSO',
    //identifierFormat: 'unspecified',
    wantAssertionsSigned: true,
    disableRequestedAuthnContext: true,
    //authnContext: [],
    //authnRequestBinding: 'HTTP-POST',
    });
    }

  15. andreacioni revised this gist Sep 10, 2022. 1 changed file with 9 additions and 6 deletions.
    15 changes: 9 additions & 6 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,21 @@
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { Injectable } from '@nestjs/common';
    import { Strategy } from 'passport-saml';
    import { User } from '../model/user';

    @Injectable()
    export class SamlStrategy extends PassportStrategy(Strategy) {
    constructor() {
    super({
    issuer: 'saml2-nest-poc',
    path: 'api/auth/sso/saml/ac',
    cert: 'MIICmzC ... LOXFc/UTyucyI=',
    entryPoint: 'http://localhost:8080/realms/master/protocol/saml',
    issuer: 'nestjs-client',
    identifierFormat: null,
    authnContext: [],
    cert: 'MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIGA1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFKs71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyjxj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVNc1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpdVa54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lkcDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiLArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/weP3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcciNBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==',
    entryPoint: 'https://samltest.id/idp/profile/SAML2/Redirect/SSO',
    //identifierFormat: 'unspecified',
    wantAssertionsSigned: true,
    disableRequestedAuthnContext: true,
    //authnContext: [],
    //authnRequestBinding: 'HTTP-POST',
    });
    }

  16. andreacioni revised this gist Sep 10, 2022. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion saml-auth.guard.ts
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,5 @@
    import { Injectable } from '@nestjs/common';
    import { AuthGuard } from '@nestjs/passport';

    @Injectable()
    export class SamlAuthGuard extends AuthGuard('saml') {}
    export class SamlAuthGuard extends AuthGuard('saml') {}
  17. andreacioni revised this gist Sep 10, 2022. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions saml-auth.guard.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    @Injectable()
    export class SamlAuthGuard extends AuthGuard('saml') {}
  18. andreacioni revised this gist Sep 10, 2022. 2 changed files with 19 additions and 13 deletions.
    19 changes: 6 additions & 13 deletions app.controller-1.ts
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,6 @@
    @Post('api/auth/sso/saml/ac')
    @UseGuards(SamlAuthGuard)
    async samlAssertionConsumer(
    @Request() req: express.Request,
    @Response() res: express.Response,
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const jwt = this.authService.getTokenForUser(req.user as User);
    this.userService.storeUser(req.user as User);
    this, res.redirect('/?jwt=' + jwt);
    }
    }
    @Get('api/auth/sso/saml/login')
    @UseGuards(SamlAuthGuard)
    async samlLogin() {
    //this route is handled by passport-saml
    return;
    }
    13 changes: 13 additions & 0 deletions app.controller-2.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    @Post('api/auth/sso/saml/ac')
    @UseGuards(SamlAuthGuard)
    async samlAssertionConsumer(
    @Request() req: express.Request,
    @Response() res: express.Response,
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const jwt = this.authService.getTokenForUser(req.user as User);
    this.userService.storeUser(req.user as User);
    this, res.redirect('/?jwt=' + jwt);
    }
    }
  19. andreacioni revised this gist Sep 10, 2022. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions app.controller-1.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    @Post('api/auth/sso/saml/ac')
    @UseGuards(SamlAuthGuard)
    async samlAssertionConsumer(
    @Request() req: express.Request,
    @Response() res: express.Response,
    ) {
    //this routes gets executed on successful assertion from IdP
    if (req.user) {
    const jwt = this.authService.getTokenForUser(req.user as User);
    this.userService.storeUser(req.user as User);
    this, res.redirect('/?jwt=' + jwt);
    }
    }
  20. andreacioni revised this gist Sep 9, 2022. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions profile.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    type Profile = {
    issuer?: string;
    sessionIndex?: string;
    nameID?: string;
    nameIDFormat?: string;
    nameQualifier?: string;
    spNameQualifier?: string;
    mail?: string; // InCommon Attribute urn:oid:0.9.2342.19200300.100.1.3
    email?: string; // `mail` if not present in the assertion
    getAssertionXml(): string; // get the raw assertion XML
    getAssertion(): object; // get the assertion XML parsed as a JavaScript object
    getSamlResponseXml(): string; // get the raw SAML response XML
    ID?: string;
    } & {
    [attributeName: string]: unknown; // arbitrary `AttributeValue`s
    };
  21. andreacioni revised this gist Sep 8, 2022. 1 changed file with 28 additions and 0 deletions.
    28 changes: 28 additions & 0 deletions saml.strategy.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { Strategy } from 'passport-saml';
    import { User } from '../model/user';

    @Injectable()
    export class SamlStrategy extends PassportStrategy(Strategy) {
    constructor() {
    super({
    path: 'api/auth/sso/saml/ac',
    cert: 'MIICmzC ... LOXFc/UTyucyI=',
    entryPoint: 'http://localhost:8080/realms/master/protocol/saml',
    issuer: 'nestjs-client',
    identifierFormat: null,
    authnContext: [],
    });
    }

    async validate(profile: any) {
    const user: User = {
    username: profile.nameID,
    role: profile.Role,
    issuer: profile.issuer,
    };

    return user;
    }
    }
  22. andreacioni revised this gist Sep 8, 2022. 1 changed file with 54 additions and 38 deletions.
    92 changes: 54 additions & 38 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,46 +1,62 @@
    <html>
    <head>
    <title>Home</title>
    </head>
    <body>
    <p id="userid">User not logged in</p>
    </body>

    <script>
    const loadProfile =async () => {
    const params = (new URL(document.location)).searchParams;
    let jwt;

    if(params.has("jwt")) {
    jwt = params.get("jwt");
    localStorage.setItem('jwt', jwt);
    } else {
    jwt = localStorage.getItem('jwt')
    <script>
    const goToLoginPage = () => {
    document.getElementById("user-profile-div").style = 'display: none;'
    document.getElementById("login-div").style = ''
    }

    const goToProfilePage = () => {
    document.getElementById("user-profile-div").style = ''
    document.getElementById("login-div").style = 'display: none;'
    }

    const loadProfile =async () => {
    const params = (new URL(document.location)).searchParams;
    let jwt;

    if(params.has("jwt")) {
    jwt = params.get("jwt");
    localStorage.setItem('jwt', jwt);
    } else {
    jwt = localStorage.getItem('jwt')
    }


    const options = jwt ? {
    headers: {'Authorization': 'Bearer ' + jwt}
    } : undefined;

    const res = await fetch("/api/profile", options);

    if(!res.ok) {
    localStorage.removeItem('jwt');
    goToLoginPage()
    return
    } else {
    const json = await res.json()

    goToProfilePage()
    document.getElementById("userid").innerHTML = json.username;
    }
    }


    const options = jwt ? {
    headers: {'Authorization': 'Bearer ' + jwt}
    } : undefined;

    const res = await fetch("/api/profile", options);

    if(!res.ok) {

    const logout = () => {
    localStorage.removeItem('jwt');
    window.location.href = '/api/auth/sso/saml/login'
    return
    } else {
    const json = await res.json()

    document.getElementById("userid").innerHTML = json.username;
    goToLoginPage()
    }



    }

    loadProfile()

    </script>
    </head>
    <body onload="loadProfile()">
    <div id="login-div">
    <p>User not logged in</p>
    <p><a id="login" href="/api/auth/sso/saml/login">Log In</a></p>
    </div>
    <div style="display: none;" id="user-profile-div">
    <p>Hello <span id="userid"></span>!</p>
    <p><a id="logout" href="#" onclick="logout()">Log Out</a></p>
    </div>

    </script>
    </body>
    </html>
  23. andreacioni revised this gist Sep 8, 2022. 1 changed file with 46 additions and 0 deletions.
    46 changes: 46 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    <html>
    <head>
    <title>Home</title>
    </head>
    <body>
    <p id="userid">User not logged in</p>
    </body>

    <script>
    const loadProfile =async () => {
    const params = (new URL(document.location)).searchParams;
    let jwt;

    if(params.has("jwt")) {
    jwt = params.get("jwt");
    localStorage.setItem('jwt', jwt);
    } else {
    jwt = localStorage.getItem('jwt')
    }


    const options = jwt ? {
    headers: {'Authorization': 'Bearer ' + jwt}
    } : undefined;

    const res = await fetch("/api/profile", options);

    if(!res.ok) {
    localStorage.removeItem('jwt');
    window.location.href = '/api/auth/sso/saml/login'
    return
    } else {
    const json = await res.json()

    document.getElementById("userid").innerHTML = json.username;
    }



    }

    loadProfile()


    </script>
    </html>
  24. andreacioni created this gist Sep 8, 2022.
    4 changes: 4 additions & 0 deletions app.controller.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    @Get()
    async homepage(@Response() res: express.Response) {
    res.sendFile(resolve('web/index.html'));
    }