import { inject , injectable } from '@loopback/core' ; import { asSpecEnhancer , HttpErrors , mergeSecuritySchemeToSpec , OASEnhancer , OpenApiSpec , Request , } from '@loopback/rest' ; import { UserProfile } from '@loopback/security' ; import { asAuthStrategy , AuthenticationStrategy } from '../../../types' ; import { BasicAuthenticationStrategyBindings } from '../keys' ; import { BasicAuthenticationUserService } from '../services/basic-auth-user-service' ; export interface BasicAuthenticationStrategyCredentials { username : string ; password : string ; } @ injectable ( asAuthStrategy , asSpecEnhancer ) export class BasicAuthenticationStrategy implements AuthenticationStrategy , OASEnhancer { name = 'basic' ; constructor ( @ inject ( BasicAuthenticationStrategyBindings . USER_SERVICE ) private userService ) { } async authenticate ( request ) { const credentials = this . extractCredentials ( request ) ; const user = await this . userService . verifyCredentials ( credentials ) ; const userProfile = this . userService . convertToUserProfile ( user ) ; return userProfile ; } extractCredentials ( request ) { if ( ! request . headers . authorization ) { throw new HttpErrors . Unauthorized ( `Authorization header not found.` ) ; } const authHeaderValue = request . headers . authorization ; if ( ! authHeaderValue . startsWith ( 'Basic' ) ) { throw new HttpErrors . Unauthorized ( `Authorization header is not of type 'Basic'.` ) ; } const parts = authHeaderValue . split ( ' ' ) ; if ( parts . length !== 2 ) throw new HttpErrors . Unauthorized ( `Authorization header value has too many parts. It must follow the pattern: 'Basic xxyyzz' where xxyyzz is a base64 string.` ) ; const encryptedCredentails = parts [ 1 ] ; const decryptedCredentails = Buffer . from ( encryptedCredentails , 'base64' ) . toString ( 'utf8' ) ; const decryptedParts = decryptedCredentails . split ( ':' ) ; if ( decryptedParts . length !== 2 ) { throw new HttpErrors . Unauthorized ( `Authorization header 'Basic' value does not contain two parts separated by ':'.` ) ; } const creds = { username : decryptedParts [ 0 ] , password : decryptedParts [ 1 ] , } ; return creds ; } modifySpec ( spec ) { return mergeSecuritySchemeToSpec ( spec , this . name , { type : 'http' , scheme : 'basic' , } ) ; } }