Skip to content

Commit

Permalink
Angular oauth2 / use ProjectFile
Browse files Browse the repository at this point in the history
  • Loading branch information
Bolo89 committed May 16, 2022
1 parent d515cec commit ba158bb
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import static tech.jhipster.lite.generator.project.domain.Constants.MAIN_WEBAPP;
import static tech.jhipster.lite.generator.project.domain.DefaultConfig.BASE_NAME;

import java.util.List;
import tech.jhipster.lite.error.domain.GeneratorException;
import tech.jhipster.lite.generator.client.angular.common.domain.AngularCommonService;
import tech.jhipster.lite.generator.packagemanager.npm.domain.NpmService;
import tech.jhipster.lite.generator.project.domain.Project;
import tech.jhipster.lite.generator.project.domain.ProjectFile;
import tech.jhipster.lite.generator.project.domain.ProjectRepository;

public class AngularOauth2DomainService implements AngularOauth2Service {
Expand Down Expand Up @@ -54,9 +56,18 @@ private void addDependencies(Project project) {

private void addFiles(Project project) {
project.addDefaultConfig(BASE_NAME);
AngularOauth2
List<ProjectFile> projectFiles = AngularOauth2
.getFilesToAdd()
.forEach((fileName, path) -> projectRepository.template(project, getPath(SOURCE_WEBAPP, path), fileName, getPath(MAIN_WEBAPP, path)));
.entrySet()
.stream()
.map(e ->
ProjectFile
.forProject(project)
.withSource(getPath(SOURCE_WEBAPP, e.getValue()), e.getKey())
.withDestinationFolder(getPath(MAIN_WEBAPP, e.getValue()))
)
.toList();
projectRepository.add(projectFiles);
}

private void updateExistingFiles(Project project) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {TestBed} from '@angular/core/testing';
import { TestBed } from '@angular/core/testing';

import {HttpAuthInterceptor} from './http-auth.interceptor';
import {Oauth2AuthService} from './oauth2-auth.service';
import {HttpHandler, HttpRequest} from '@angular/common/http';
import {lastValueFrom, of} from 'rxjs';
import { HttpAuthInterceptor } from './http-auth.interceptor';
import { Oauth2AuthService } from './oauth2-auth.service';
import { HttpHandler, HttpRequest } from '@angular/common/http';
import { lastValueFrom, of } from 'rxjs';
import Mock = jest.Mock;

const URL = 'http://localhost:8080/api/dummy';
Expand All @@ -15,7 +15,7 @@ const buildHttpRequest = () => {
return originalRequest.clone({
headers: originalRequest.headers.append('ContentType', 'application/json'),
});
}
};

describe('HttpAuthInterceptor', () => {
let interceptor: HttpAuthInterceptor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import {Oauth2AuthService} from './oauth2-auth.service';
import { Oauth2AuthService } from './oauth2-auth.service';

@Injectable()
export class HttpAuthInterceptor implements HttpInterceptor {
constructor(private oauth2AuthService: Oauth2AuthService) {}

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Oauth2AuthService} from './oauth2-auth.service';
import {TestBed} from '@angular/core/testing';
import Keycloak, {KeycloakError, KeycloakInitOptions, KeycloakInstance, KeycloakPromise} from 'keycloak-js';
import {lastValueFrom} from 'rxjs';
import { Oauth2AuthService } from './oauth2-auth.service';
import { TestBed } from '@angular/core/testing';
import Keycloak, { KeycloakError, KeycloakInitOptions, KeycloakInstance, KeycloakPromise } from 'keycloak-js';
import { lastValueFrom } from 'rxjs';
import SpyInstance = jest.SpyInstance;

jest.mock('keycloak-js', () => ({
Expand All @@ -25,8 +25,8 @@ jest.mock('../../environments/environment', () => ({
keycloak: {
url: 'http://localhost:1234',
realm: 'jhipster',
client_id: 'web_app'
}
client_id: 'web_app',
},
},
}));

Expand Down Expand Up @@ -71,7 +71,8 @@ describe('Oauth2 Auth Service', () => {

it('should init refresh token and return true when the user is authenticated', async () => {
// Given
jest.spyOn(keycloakInstance, 'init')
jest
.spyOn(keycloakInstance, 'init')
.mockReturnValue(Promise.resolve(true).then() as unknown as KeycloakPromise<boolean, KeycloakError>);

// When
Expand All @@ -92,7 +93,8 @@ describe('Oauth2 Auth Service', () => {

it('should reload window and return false when the user is not authenticated', async () => {
// Given
jest.spyOn(keycloakInstance, 'init')
jest
.spyOn(keycloakInstance, 'init')
.mockReturnValue(Promise.resolve(false).then() as unknown as KeycloakPromise<boolean, KeycloakError>);

// When
Expand Down Expand Up @@ -126,8 +128,7 @@ describe('Oauth2 Auth Service', () => {
jest.spyOn(Date, 'now').mockReturnValue(1651318847714); // 2022-04-30 13:40:47

let updateTokenPromise = Promise.resolve(false);
jest.spyOn(keycloakInstance, 'updateToken')
.mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);
jest.spyOn(keycloakInstance, 'updateToken').mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);

// When
await lastValueFrom(service.initAuthentication());
Expand All @@ -143,8 +144,7 @@ describe('Oauth2 Auth Service', () => {
it('should call update token and log debug "refreshed" message when token is refreshed', async () => {
// Given
let updateTokenPromise = Promise.resolve(true);
jest.spyOn(keycloakInstance, 'updateToken')
.mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);
jest.spyOn(keycloakInstance, 'updateToken').mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);

// When
await lastValueFrom(service.initAuthentication());
Expand All @@ -160,8 +160,7 @@ describe('Oauth2 Auth Service', () => {
it('should call update token and log error message on error', async () => {
// Given
let updateTokenPromise = Promise.reject(new Error('unknown error'));
jest.spyOn(keycloakInstance, 'updateToken')
.mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);
jest.spyOn(keycloakInstance, 'updateToken').mockReturnValue(updateTokenPromise as unknown as KeycloakPromise<boolean, boolean>);

// When
await lastValueFrom(service.initAuthentication());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Injectable } from '@angular/core';
import Keycloak, { KeycloakConfig, KeycloakInstance } from 'keycloak-js';
import { from, Observable, tap } from 'rxjs';
import { environment } from '../../environments/environment';

const MIN_TOKEN_VALIDITY_SECONDS = 70;
const REFRESH_TOKEN_TIMEOUT_MS = 6000;

@Injectable({ providedIn: 'root' })
export class Oauth2AuthService {
private keycloak!: KeycloakInstance;

get token(): string | undefined {
return this.keycloak.token;
}

get isAuthenticated(): boolean | undefined {
return this.keycloak.authenticated;
}

initAuthentication(): Observable<boolean> {
const config: KeycloakConfig = {
url: environment.keycloak.url,
realm: environment.keycloak.realm,
clientId: environment.keycloak.client_id,
};
this.keycloak = Keycloak(config);

return from(this.keycloak.init({ onLoad: 'login-required', checkLoginIframe: false })).pipe(
tap(authenticated => {
if (!authenticated) {
window.location.reload();
} else {
console.debug('Authenticated');
}
}),
tap(() => {
this.initUpdateTokenRefresh();
})
);
}

logout(): void {
this.keycloak.logout();
}

private initUpdateTokenRefresh(): void {
setInterval(
() =>
this.keycloak
.updateToken(MIN_TOKEN_VALIDITY_SECONDS)
.then(refreshed => {
if (refreshed) {
console.debug('Token refreshed');
} else {
const exp = this.keycloak.tokenParsed!.exp!;
const timeSkew = this.keycloak.timeSkew!;
console.debug('Token not refreshed, valid for ' + Math.round(exp + timeSkew - Date.now() / 1000) + ' seconds');
}
})
.catch(e => console.error('Failed to refresh token: ' + e)),
REFRESH_TOKEN_TIMEOUT_MS
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import {By} from '@angular/platform-browser';
import { By } from '@angular/platform-browser';
import { LoginComponent } from './login.component';
import {Oauth2AuthService} from '../auth/oauth2-auth.service';
import { Oauth2AuthService } from '../auth/oauth2-auth.service';

describe('LoginComponent', () => {
let component: LoginComponent;
Expand All @@ -12,9 +12,8 @@ describe('LoginComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
declarations: [LoginComponent],
}).compileComponents();
});

beforeEach(() => {
Expand All @@ -36,5 +35,5 @@ describe('LoginComponent', () => {
fixture.debugElement.query(By.css('#btn-logout')).nativeElement.click();

expect(oauth2AuthService.logout).toHaveBeenCalledWith();
})
});
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Component } from '@angular/core';
import {Oauth2AuthService} from '../auth/oauth2-auth.service';
import { Oauth2AuthService } from '../auth/oauth2-auth.service';

@Component({
selector: 'jh-lite-login',
templateUrl: './login.component.html',
styleUrls: [],
})
export class LoginComponent {
constructor(private oauth2AuthService: Oauth2AuthService) { }
constructor(private oauth2AuthService: Oauth2AuthService) {}

logout(): void {
this.oauth2AuthService.logout();
Expand Down
Loading

0 comments on commit ba158bb

Please sign in to comment.