horse
horse copied to clipboard
Any Changes
Hi Vinicius, I have made some changes to unit Horse.BasicAuthentication.pas . This change is necessary because if you deploy an apache module the "Req.Heades[Config.Header]" does not read any value. Another change that I have made is to extend the possibility of passing the THorseReq value to the Authentication procedure.
I attach the code in this message if you can add it to the source code.
unit Horse.BasicAuthentication;
{$IF DEFINED(FPC)} {$MODE DELPHI}{$H+} {$ENDIF}
interface
uses {$IF DEFINED(FPC)} SysUtils, base64, Classes, {$ELSE} System.SysUtils, System.NetEncoding, System.Classes, {$ENDIF} Horse, Horse.Commons;
const AUTHORIZATION = 'Authorization'; REALM_MESSAGE = 'Enter credentials';
type
IHorseBasicAuthenticationConfig = interface
['{DB16765F-156C-4BC1-8EDE-183CA9FE1985}']
function Header(const AValue: string): IHorseBasicAuthenticationConfig; overload;
function Header: string; overload;
function RealmMessage(const AValue: string): IHorseBasicAuthenticationConfig; overload;
function RealmMessage: string; overload;
function SkipRoutes(const AValues: TArray
THorseBasicAuthenticationConfig = class(TInterfacedObject, IHorseBasicAuthenticationConfig)
private
FHeader: string;
FRealmMessage: string;
FSkipRoutes: TArray
type THorseBasicAuthentication = {$IF NOT DEFINED(FPC)} reference to {$ENDIF} function(const AUsername, APassword: string; Req: THorseRequest): Boolean;
procedure Middleware(Req: THorseRequest; Res: THorseResponse; Next: {$IF DEFINED(FPC)} TNextProc {$ELSE} TProc {$ENDIF}); function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication): THorseCallback; overload; function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication; Req: THorseRequest): THorseCallback; overload; function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication; const AConfig: IHorseBasicAuthenticationConfig): THorseCallback; overload;
implementation
var Config: IHorseBasicAuthenticationConfig; Authenticate: THorseBasicAuthentication;
function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication): THorseCallback; begin Result := HorseBasicAuthentication(AAuthenticate, THorseBasicAuthenticationConfig.New); end;
function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication; Req: THorseRequest): THorseCallback; begin Result := HorseBasicAuthentication(AAuthenticate, THorseBasicAuthenticationConfig.New); end;
function HorseBasicAuthentication(const AAuthenticate: THorseBasicAuthentication; const AConfig: IHorseBasicAuthenticationConfig): THorseCallback; begin Config := AConfig; Authenticate := AAuthenticate; Result := Middleware; end;
procedure Middleware(Req: THorseRequest; Res: THorseResponse; Next: {$IF DEFINED(FPC)} TNextProc {$ELSE} TProc {$ENDIF}); const BASIC_AUTH = 'basic '; var LBasicAuthenticationEncode: string; LBase64String: string; LBasicAuthenticationDecode: TStringList; LIsAuthenticated: Boolean; LPathInfo: string; begin LPathInfo := Req.RawWebRequest.PathInfo; if LPathInfo = EmptyStr then LPathInfo := '/'; if MatchRoute(LPathInfo, Config.SkipRoutes) then begin Next(); Exit; end;
LBasicAuthenticationEncode := Req.Headers[Config.Header];
//* Modifica per provare a leggere il dato dalla RawWebRequest ..... if LBasicAuthenticationEncode.Trim.IsEmpty then LBasicAuthenticationEncode := Req.RawWebRequest.GetFieldByName(Config.Header);
if LBasicAuthenticationEncode.Trim.IsEmpty and not Req.Query.TryGetValue(Config.Header, LBasicAuthenticationEncode) then begin Res.Send('Authorization not found').Status(THTTPStatus.Unauthorized).RawWebResponse {$IF DEFINED(FPC)} .WWWAuthenticate := Format('Basic realm=%s', [Config.RealmMessage]); {$ELSE} .Realm := Config.RealmMessage; {$ENDIF} raise EHorseCallbackInterrupted.Create; end;
if not LBasicAuthenticationEncode.Trim.ToLower.StartsWith(BASIC_AUTH) then begin Res.Send('Invalid authorization type').Status(THTTPStatus.Unauthorized); raise EHorseCallbackInterrupted.Create; end;
LBasicAuthenticationDecode := TStringList.Create; try LBasicAuthenticationDecode.Delimiter := ':'; LBasicAuthenticationDecode.StrictDelimiter := True; LBase64String := LBasicAuthenticationEncode.Trim.Replace(BASIC_AUTH, '', [rfIgnoreCase]); LBasicAuthenticationDecode.DelimitedText := {$IF DEFINED(FPC)}DecodeStringBase64(LBase64String){$ELSE}TBase64Encoding.base64.Decode(LBase64String){$ENDIF};
try
LIsAuthenticated := Authenticate(LBasicAuthenticationDecode.Strings[0], LBasicAuthenticationDecode.Strings[1], Req);
except
on E: exception do
begin
Res.Send(E.Message).Status(THTTPStatus.InternalServerError);
raise EHorseCallbackInterrupted.Create;
end;
end;
finally LBasicAuthenticationDecode.Free; end;
if not LIsAuthenticated then begin Res.Send('Unauthorized').Status(THTTPStatus.Unauthorized); raise EHorseCallbackInterrupted.Create; end;
Next(); end;
{ THorseBasicAuthenticationConfig }
constructor THorseBasicAuthenticationConfig.Create; begin FHeader := AUTHORIZATION; FRealmMessage := REALM_MESSAGE; FSkipRoutes := []; end;
function THorseBasicAuthenticationConfig.Header: string; begin Result := FHeader; end;
function THorseBasicAuthenticationConfig.Header(const AValue: string): IHorseBasicAuthenticationConfig; begin FHeader := AValue; Result := Self; end;
class function THorseBasicAuthenticationConfig.New: IHorseBasicAuthenticationConfig; begin Result := THorseBasicAuthenticationConfig.Create; end;
function THorseBasicAuthenticationConfig.RealmMessage(const AValue: string): IHorseBasicAuthenticationConfig; begin FRealmMessage := AValue; Result := Self; end;
function THorseBasicAuthenticationConfig.RealmMessage: string; begin Result := FRealmMessage; end;
function THorseBasicAuthenticationConfig.SkipRoutes(const AValue: string): IHorseBasicAuthenticationConfig; begin Result := SkipRoutes([AValue]); end;
function THorseBasicAuthenticationConfig.SkipRoutes(const AValues: TArray
function THorseBasicAuthenticationConfig.SkipRoutes: TArray
end.
An example, use the authorization method.
function DoBasicAuthentication(const Username, Password: string; Req: THorseRequest): Boolean; var Users: TServiceUsers; Config: TConfigLogin; begin Users := TServiceUsers.Create; try {$IFDEF HORSE_APACHE} var sx : String := Req.RawWebRequest.PathInfo; var sp : String := Req.RawWebRequest.PathTranslated; sp := sp.Replace('',''); sx := sx.Replace('',''); sp := sp.Replace(sx,'') + '/BEEAPI_CFG.ini';
Users.fHomeSetDir := sp;
Config.HomeSetDir := sp;
{$ENDIF}
var LoggingDIR : String := Config.LogDir;
WriteLOG('CALL : DoBasicAuthentication .... ', LoggingDIR {$IFDEF HORSE_APACHE}, 'libbee_api'{$ENDIF});
Users.ConnectDB;
Result := Users.IsValid(Username, Password);
finally Users.Free; end; end;
Hello @AndreaLai74 Couldn't you send a Pull Request to the middleware? Or send us the file to facilitate. Thanks
Thanks
@dliocode isso resolveria com o seu PR ne?
sim