auth: Split randomBase64UrlString in two functions

add test for BufferToBase64Url and toAuthTokenDto

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2021-01-23 19:04:00 +01:00 committed by David Mehren
parent 508ad26771
commit e6dc8c7678
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
2 changed files with 37 additions and 12 deletions

View file

@ -112,7 +112,7 @@ describe('AuthService', () => {
it('getAuthToken', async () => { it('getAuthToken', async () => {
const token = 'testToken'; const token = 'testToken';
authToken.accessTokenHash = await service.hashPassword(token); authToken.accessTokenHash = await service.hashPassword(token);
const authTokenFromCall = await service.getAuthToken( const authTokenFromCall = await service.getAuthTokenAndValidate(
authToken.keyId, authToken.keyId,
token, token,
); );
@ -154,4 +154,19 @@ describe('AuthService', () => {
expect(token.lastUsed).toBeUndefined(); expect(token.lastUsed).toBeUndefined();
expect(token.secret.startsWith(token.keyId)).toBeTruthy(); expect(token.secret.startsWith(token.keyId)).toBeTruthy();
}); });
it('BufferToBase64Url', () => {
expect(
service.BufferToBase64Url(Buffer.from('testsentence is a test sentence')),
).toEqual('dGVzdHNlbnRlbmNlIGlzIGEgdGVzdCBzZW50ZW5jZQ');
});
it('toAuthTokenDto', async () => {
const tokenDto = await service.toAuthTokenDto(authToken);
expect(tokenDto.keyId).toEqual(authToken.keyId);
expect(tokenDto.lastUsed).toBeNull();
expect(tokenDto.label).toEqual(authToken.identifier);
expect(tokenDto.validUntil).toBeNull();
expect(tokenDto.created).toEqual(authToken.createdAt.getTime());
});
}); });

View file

@ -30,7 +30,7 @@ export class AuthService {
async validateToken(token: string): Promise<User> { async validateToken(token: string): Promise<User> {
const parts = token.split('.'); const parts = token.split('.');
const accessToken = await this.getAuthToken(parts[0], parts[1]); const accessToken = await this.getAuthTokenAndValidate(parts[0], parts[1]);
const user = await this.usersService.getUserByUsername( const user = await this.usersService.getUserByUsername(
accessToken.user.userName, accessToken.user.userName,
); );
@ -42,20 +42,26 @@ export class AuthService {
} }
async hashPassword(cleartext: string): Promise<string> { async hashPassword(cleartext: string): Promise<string> {
// hash the password with bcrypt and 2^16 iterations // hash the password with bcrypt and 2^12 iterations
return hash(cleartext, 12); return hash(cleartext, 12);
} }
async checkPassword(cleartext: string, password: string): Promise<boolean> { async checkPassword(cleartext: string, password: string): Promise<boolean> {
// hash the password with bcrypt and 2^16 iterations
return compare(cleartext, password); return compare(cleartext, password);
} }
randomBase64UrlString(length = 64): string { async randomString(length: number): Promise<Buffer> {
// This is necessary as the is no base64url encoding in the toString method // This is necessary as the is no base64url encoding in the toString method
// but as can be seen on https://tools.ietf.org/html/rfc4648#page-7 // but as can be seen on https://tools.ietf.org/html/rfc4648#page-7
// base64url is quite easy buildable from base64 // base64url is quite easy buildable from base64
return randomBytes(length) if (length <= 0) {
return null;
}
return randomBytes(length);
}
BufferToBase64Url(text: Buffer): string {
return text
.toString('base64') .toString('base64')
.replace('+', '-') .replace('+', '-')
.replace('/', '_') .replace('/', '_')
@ -68,9 +74,10 @@ export class AuthService {
until: number, until: number,
): Promise<AuthTokenWithSecretDto> { ): Promise<AuthTokenWithSecretDto> {
const user = await this.usersService.getUserByUsername(userName); const user = await this.usersService.getUserByUsername(userName);
const secret = this.randomBase64UrlString(); const secret = await this.randomString(64);
const keyId = this.randomBase64UrlString(8); const keyId = this.BufferToBase64Url(await this.randomString(8));
const accessToken = await this.hashPassword(secret); const accessTokenString = await this.hashPassword(secret.toString());
const accessToken = this.BufferToBase64Url(Buffer.from(accessTokenString));
let token; let token;
if (until === 0) { if (until === 0) {
token = AuthToken.create(user, identifier, keyId, accessToken); token = AuthToken.create(user, identifier, keyId, accessToken);
@ -89,7 +96,10 @@ export class AuthService {
await this.authTokenRepository.save(accessToken); await this.authTokenRepository.save(accessToken);
} }
async getAuthToken(keyId: string, token: string): Promise<AuthToken> { async getAuthTokenAndValidate(
keyId: string,
token: string,
): Promise<AuthToken> {
const accessToken = await this.authTokenRepository.findOne({ const accessToken = await this.authTokenRepository.findOne({
where: { keyId: keyId }, where: { keyId: keyId },
relations: ['user'], relations: ['user'],
@ -149,9 +159,9 @@ export class AuthService {
authToken: AuthToken | null | undefined, authToken: AuthToken | null | undefined,
secret: string, secret: string,
): AuthTokenWithSecretDto | null { ): AuthTokenWithSecretDto | null {
const tokeDto = this.toAuthTokenDto(authToken); const tokenDto = this.toAuthTokenDto(authToken);
return { return {
...tokeDto, ...tokenDto,
secret: secret, secret: secret,
}; };
} }