Commit 8b05fa97 authored by Merzough Münker's avatar Merzough Münker
Browse files

fix: support disabled oauth

parent fed7960a
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -12,7 +12,10 @@ import {
  withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { provideServiceWorker } from '@angular/service-worker';
import { BearerTokenInterceptor } from '@rxap/authentication';
import {
  BearerTokenInterceptor,
  withDisabledAuthentication,
} from '@rxap/authentication';
import { ProvideEnvironment } from '@rxap/environment';
import { ProvideChangelog } from '@rxap/ngx-changelog';
import {
@@ -58,7 +61,7 @@ export const appConfig: ApplicationConfig = {
      dummyClientSecret: 'geheim',
      redirectUri: window.location.origin + '/index.html',
      // silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
    })),
    }), withDisabledAuthentication()),
    provideServiceWorker(
      'ngsw-worker.js',
      { enabled: environment.serviceWorker, registrationStrategy: 'registerWhenStable:30000' },
+11 −1
Original line number Diff line number Diff line
import { InjectionToken } from '@angular/core';
import {
  InjectionToken,
  Provider,
} from '@angular/core';
import { BehaviorSubject } from 'rxjs';

export const RXAP_AUTHENTICATION_DEACTIVATED = new InjectionToken<boolean>('rxap/authentication/deactivated');
@@ -20,3 +23,10 @@ export const RXAP_INITIAL_AUTHENTICATION_STATE = new InjectionToken<boolean>('rx
  providedIn: 'root',
  factory: () => false,
});

export function withDisabledAuthentication(disabled = true): Provider {
  return {
    provide: RXAP_AUTHENTICATION_DEACTIVATED,
    useValue: disabled,
  };
}
+10 −1
Original line number Diff line number Diff line
@@ -3,11 +3,20 @@ import {
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
} from '@angular/router';
import { RxapAuthenticationService } from '@rxap/authentication';
import {
  RXAP_AUTHENTICATION_DEACTIVATED,
  RxapAuthenticationService,
} from '@rxap/authentication';
import { AuthenticationService } from './authentication.service';

export async function AuthenticationGuard(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {

  const isAuthDisabled = inject(RXAP_AUTHENTICATION_DEACTIVATED, { optional: true }) ?? false;

  if (isAuthDisabled) {
    console.warn('Authentication is disabled!');
    return true;
  }

  const authService = inject(RxapAuthenticationService);

+61 −14
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import {
  AuthenticationEventType,
  IAuthenticationService,
  RXAP_AUTHENTICATION_ACCESS_TOKEN,
  RXAP_AUTHENTICATION_DEACTIVATED,
} from '@rxap/authentication';
import { isDefined } from '@rxap/rxjs';
import {
@@ -20,27 +21,56 @@ import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import {
  BehaviorSubject,
  distinctUntilChanged,
  EMPTY,
  firstValueFrom,
  Observable,
  startWith,
  Subject,
} from 'rxjs';
import { map } from 'rxjs/operators';

const JONE_DOE_JWT = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';

@Injectable()
export class AuthenticationService implements IAuthenticationService {
  events$: Observable<AuthenticationEvent>;
  isAuthenticated$ = new BehaviorSubject<boolean | null>(null);
  events$: Observable<AuthenticationEvent> = EMPTY;
  public readonly isAuthenticated$ = new BehaviorSubject<boolean | null>(null);

  /**
   * Is only used when authentication is disabled to emit the events
   * @private
   */
  private readonly _events$ = new Subject<AuthenticationEvent>();

  constructor(
    private readonly oauthService: OAuthService,
    @Optional()
    @Inject(AUTH_CONFIG)
      authConfig: AuthConfig,
    private readonly authConfig: AuthConfig,
    @Inject(RXAP_AUTHENTICATION_ACCESS_TOKEN)
    private readonly authenticationAccessToken: BehaviorSubject<AuthenticationAccessToken | null>,
    @Inject(RXAP_AUTHENTICATION_DEACTIVATED)
    private readonly isAuthDisabled: boolean,
  ) {
    if (authConfig) {
      this.oauthService.configure(authConfig);
    if (this.isAuthDisabled) {
      this.events$ = this._events$.asObservable();
      this.linkEventsAndIsAuthenticated();
      this._events$.next({
        type: AuthenticationEventType.OnAuthSuccess,
        payload: null,
      });
      this.authenticationAccessToken.next({
        token: JONE_DOE_JWT,
        valid: true,
      });
    } else {
      this.init();
    }
  }

  init() {
    if (this.authConfig) {
      this.oauthService.configure(this.authConfig);
    }
    this.events$ = this.oauthService.events.pipe(
      map(event => {
@@ -74,11 +104,7 @@ export class AuthenticationService implements IAuthenticationService {
      }),
      isDefined(),
    );
    this.events$.pipe(
      map(event => event ? event.type === AuthenticationEventType.OnAuthSuccess : null),
      distinctUntilChanged(),
      startWith(null),
    ).subscribe(this.isAuthenticated$);
    this.linkEventsAndIsAuthenticated();

    // Use setStorage to use sessionStorage or another implementation of the TS-type Storage
    // instead of localStorage
@@ -92,16 +118,37 @@ export class AuthenticationService implements IAuthenticationService {
    this.oauthService.loadDiscoveryDocumentAndTryLogin().then(status => {
      this.isAuthenticated$.next(status);
    });

  }

  async signOut(): Promise<void> {
    if (this.isAuthDisabled) {
      this._events$.next({
        type: AuthenticationEventType.OnLogout,
        payload: null,
      });
    } else {
      this.oauthService.logOut();
    }
  }

  signIn() {
    if (this.isAuthDisabled) {
      this._events$.next({
        type: AuthenticationEventType.OnAuthSuccess,
        payload: null,
      });
    } else {
      this.oauthService.initLoginFlow();
    }
  }

  private linkEventsAndIsAuthenticated() {
    this.events$.pipe(
      map(event => event ? event.type === AuthenticationEventType.OnAuthSuccess : null),
      distinctUntilChanged(),
      startWith(null),
    ).subscribe(this.isAuthenticated$);
  }

  isAuthenticated(): Promise<boolean> {
    return firstValueFrom(this.isAuthenticated$.pipe(isDefined()));