-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e664564
commit 6064193
Showing
20 changed files
with
267 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
|
||
describe('Authentication', () => { | ||
const urlRegistration = 'http://localhost:8010/auth/register'; | ||
const urlLogin = 'http://localhost:8010/auth/login'; | ||
|
||
beforeEach(() => { | ||
|
||
}); | ||
|
||
describe('Protected Routes', () => { | ||
|
||
it('should grant access to protected routes when attempt made with a valid token', () => { | ||
/** Given */ | ||
|
||
/** When */ | ||
|
||
/** Then */ | ||
|
||
}) | ||
|
||
it('should redirect user to /home when attempt made to access protected routes without valid token', () => { | ||
/** Given */ | ||
|
||
/** When */ | ||
|
||
/** Then */ | ||
|
||
}) | ||
|
||
it('should allow access to unprotected routes without valid token', () => { | ||
/** Given */ | ||
|
||
/** When */ | ||
|
||
/** Then */ | ||
|
||
}) | ||
}) | ||
|
||
describe('Registration', () => { | ||
|
||
}) | ||
|
||
describe('Login', () => { | ||
|
||
}) | ||
|
||
describe('Logout', () => { | ||
|
||
}) | ||
|
||
}) | ||
|
||
/** What authentication rules should the webapp have? */ | ||
/** | ||
* Protected routes | ||
* All routes (except /home ; /login ; /registration), should require a valid JWT to have access | ||
* If no JWT, should be routed to /home | ||
* Login | ||
* Should sign user in, then route to /home | ||
* Failed login should present the reason and give user another chance (unlimited) | ||
* Registration | ||
* Should create new account, then login | ||
* Failed registration should present the reason and give user another chance (unlimited) | ||
* Logout | ||
* Should clear JWT and route back to /home | ||
* | ||
* Note :: reset password not to be considered as part of 0.2.x Authentication | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,28 @@ | ||
import { Routes} from '@angular/router'; | ||
import { Routes } from '@angular/router'; | ||
import { FitTrackComponent } from "./presentation/fit-track/fit-track.component"; | ||
import { HomeComponent } from "./presentation/home/home.component"; | ||
import { XComponent } from "./presentation/x/x.component"; | ||
import { YComponent } from "./presentation/y/y.component"; | ||
import {LoginComponent} from "./presentation/login/login.component"; | ||
import {AuthGuard} from "./core/guard/auth-guard"; | ||
import { LoginComponent } from "./presentation/login/login.component"; | ||
import { AuthGuard } from "./core/guard/auth-guard"; | ||
|
||
export const routes: Routes = [ | ||
{ path: 'auth', component: LoginComponent }, | ||
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard] }, | ||
/** Open Routes */ | ||
{ | ||
path: 'auth', | ||
children: [ | ||
{ path: 'login', component: LoginComponent }, | ||
{ path: 'register', component: LoginComponent }, | ||
], | ||
}, | ||
{ path: 'home', component: HomeComponent }, | ||
|
||
/** Protected Routes */ | ||
{ path: 'x', component: XComponent, canActivate: [AuthGuard] }, | ||
{ path: 'y', component: YComponent, canActivate: [AuthGuard] }, | ||
{ path: 'fit-track', component: FitTrackComponent, canActivate: [AuthGuard] }, | ||
|
||
|
||
/** Default */ | ||
{ path: '**', redirectTo: 'home' } | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Entity } from "./entity"; | ||
|
||
/** | ||
* Authorisation Token Class | ||
* | ||
* @author J. R. Smith | ||
* @since 17th April 2024 | ||
*/ | ||
export class Token extends Entity { | ||
sub: string = ''; | ||
exp: number = 0; | ||
iat: number = 0; | ||
userId: number = 0; | ||
} |
File renamed without changes.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Injectable } from "@angular/core"; | ||
import { TokenService } from "./token.service"; | ||
import { HttpService } from "../http/http.service"; | ||
import { environment } from "../../../../environments/environment"; | ||
|
||
const BASE_URL = environment.services.security.baseUrl; | ||
const URI = environment.services.security.uri; | ||
|
||
@Injectable({ | ||
providedIn: 'root' | ||
}) | ||
export class AuthenticationService { | ||
|
||
constructor(private http: HttpService, private tokenService: TokenService) { } | ||
|
||
/** Attempt to sign in a user to Cardinal with given credentials */ | ||
async login() { | ||
this.http.post(BASE_URL, URI.auth.login, ''); | ||
|
||
this.tokenService.set('a_token') | ||
|
||
// Note :: in login component, redirect to /home | ||
} | ||
|
||
/** Attempt to register a new Cardinal user */ | ||
async register() { | ||
this.http.post(BASE_URL, URI.auth.register, ''); | ||
|
||
// Note :: in registration component, call login and redirect to /home | ||
} | ||
|
||
/** End the user session */ | ||
logout() { | ||
this.tokenService.removeToken(); | ||
|
||
// Note :: in component, redirect to /home | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { computed, Injectable, Signal, signal, WritableSignal } from '@angular/core'; | ||
import { StorageUtil } from "../../util/storage/storage.util"; | ||
import { Token } from "../../model/token"; | ||
|
||
@Injectable({ | ||
providedIn: 'root' | ||
}) | ||
export class TokenService { | ||
|
||
private token: WritableSignal<null | string> = signal(null); | ||
private decoded: Signal<null | Token> = computed(() => this.decode(this.token())); | ||
|
||
constructor() { } | ||
|
||
/** Set authentication token in local storage */ | ||
set(token: string): void { | ||
StorageUtil.set('token', token); | ||
} | ||
|
||
/** Determine if user is signed in by presence of valid token */ | ||
hasValidToken(): boolean { | ||
this.token.update(token => StorageUtil.get('token')); | ||
|
||
const tokenEmpty = !this.decoded(); | ||
if (tokenEmpty) return false; | ||
|
||
return this.hasValidSignature() && this.hasValidExpiry(); | ||
} | ||
|
||
/** Logout user by removing token from local storage */ | ||
removeToken(): void { | ||
StorageUtil.remove('token'); | ||
} | ||
|
||
/** Determine if a token has a valid signature */ | ||
private hasValidSignature(): boolean { | ||
return true | ||
} | ||
|
||
/** Determine if a token is yet to expire */ | ||
private hasValidExpiry(): boolean { | ||
const token = this.decoded()! | ||
const expiry = new Date(1000 * token.exp); | ||
return expiry.getTime() > new Date().getTime(); | ||
} | ||
|
||
/** Decode an authorisation token */ | ||
private decode(token: string | null): Token | null { | ||
if (!token) return null | ||
|
||
const decoded: any = {}; | ||
/** TODO :: how to verify... using secret (bad idea) | ||
* is the model to soft force a login but require any actions to be authenticated on the backend (dumb client?) | ||
*/ | ||
return Token.convert(decoded); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Empty file.
File renamed without changes.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
/** | ||
* Utility to interact with LocalStorage | ||
* | ||
* @author J. R. Smith | ||
* @since 17th April 2024 | ||
*/ | ||
export class StorageUtil { | ||
|
||
/** Get the value from LocalStorage for a given key */ | ||
static get(key: string): string | null { | ||
if (typeof window !== 'undefined') { | ||
return localStorage.getItem(key); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** Set the value in LocalStorage for a given key */ | ||
static set(key: string, value: string): void { | ||
if (typeof window !== 'undefined') { | ||
localStorage.setItem(key, value); | ||
} | ||
} | ||
|
||
/** Delete the value in LocalStorage for a given key */ | ||
static remove(key: string): void { | ||
localStorage.removeItem(key); | ||
} | ||
|
||
} |
Oops, something went wrong.