{ $Project$ $Workfile$ $Revision$ $DateUTC$ $Id$ This file is part of the Indy (Internet Direct) project, and is offered under the dual-licensing agreement described on the Indy website. (http://www.indyproject.org/) Copyright: (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved. } { $Log$ } { Rev 1.5 10/26/2004 10:51:40 PM JPMugaas Updated ref. Rev 1.4 7/6/2004 4:53:46 PM DSiders Corrected spelling of Challenge in properties, methods, types. Rev 1.3 2004.02.03 5:44:40 PM czhower Name changes Rev 1.2 2004.01.22 2:05:16 PM czhower TextIsSame Rev 1.1 1/21/2004 4:21:08 PM JPMugaas InitComponent Rev 1.0 11/13/2002 08:04:16 AM JPMugaas } unit IdUserAccounts; { Original Author: Sergio Perry Date: 24/04/2001 2002-05-03 - Andrew P.Rybin - TIdCustomUserManager,TIdSimpleUserManager,UserId - universal TIdUserManagerAuthenticationEvent> Sender: TObject } interface {$i IdCompilerDefines.inc} uses Classes, IdException, IdGlobal, IdBaseComponent, IdComponent, IdStrings; type TIdUserHandle = UInt32;//ptr,object,collection.item.id or THandle TIdUserAccess = Integer; //<0-denied, >=0-accept; ex: 0-guest,1-user,2-power user,3-admin var IdUserHandleNone: TIdUserHandle = High(UInt32)-1; //Special handle: empty handle IdUserHandleBroadcast: TIdUserHandle = High(UInt32); //Special handle IdUserAccessDenied: TIdUserAccess = Low(Integer); //Special access type TIdCustomUserManagerOption = (umoCaseSensitiveUsername, umoCaseSensitivePassword); TIdCustomUserManagerOptions = set of TIdCustomUserManagerOption; TIdUserManagerAuthenticationEvent = procedure(Sender: TObject; {TIdCustomUserManager, TIdPeerThread, etc} const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess) of object; TIdUserManagerLogoffEvent = procedure(Sender: TObject; var VUserHandle: TIdUserHandle) of object; TIdCustomUserManager = class(TIdBaseComponent) protected FDomain: String; FOnAfterAuthentication: TIdUserManagerAuthenticationEvent; //3 FOnBeforeAuthentication: TIdUserManagerAuthenticationEvent;//1 FOnLogoffUser: TIdUserManagerLogoffEvent;//4 // procedure DoBeforeAuthentication(const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual; // Descendants must override this method: procedure DoAuthentication (const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual; abstract; procedure DoAfterAuthentication (const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual; procedure DoLogoffUser(var VUserHandle: TIdUserHandle); virtual; function GetOptions: TIdCustomUserManagerOptions; virtual; procedure SetDomain(const AValue: String); virtual; procedure SetOptions(const AValue: TIdCustomUserManagerOptions); virtual; // props property Domain: String read FDomain write SetDomain; property Options: TIdCustomUserManagerOptions read GetOptions write SetOptions; // events property OnBeforeAuthentication: TIdUserManagerAuthenticationEvent read FOnBeforeAuthentication write FOnBeforeAuthentication; property OnAfterAuthentication: TIdUserManagerAuthenticationEvent read FOnAfterAuthentication write FOnAfterAuthentication; property OnLogoffUser: TIdUserManagerLogoffEvent read FOnLogoffUser write FOnLogoffUser; public //Challenge user is a nice backdoor for some things we will do in a descendent class function ChallengeUser(var VIsSafe : Boolean; const AUserName : String) : String; virtual; function AuthenticateUser(const AUsername, APassword: String): Boolean; overload; function AuthenticateUser(const AUsername, APassword: String; var VUserHandle: TIdUserHandle): TIdUserAccess; overload; class function IsRegisteredUser(AUserAccess: TIdUserAccess): Boolean; procedure LogoffUser(AUserHandle: TIdUserHandle); virtual; procedure UserDisconnected(const AUser : String); virtual; function SendsChallange : Boolean; virtual; End;//TIdCustomUserManager //============================================================================= // * TIdSimpleUserManager * //============================================================================= TIdSimpleUserManager = class(TIdCustomUserManager) protected FOptions: TIdCustomUserManagerOptions; FOnAuthentication: TIdUserManagerAuthenticationEvent; // procedure DoAuthentication (const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); override; function GetOptions: TIdCustomUserManagerOptions; override; procedure SetOptions(const AValue: TIdCustomUserManagerOptions); override; published property Domain; property Options; // events property OnBeforeAuthentication; property OnAuthentication: TIdUserManagerAuthenticationEvent read FOnAuthentication write FOnAuthentication; property OnAfterAuthentication; property OnLogoffUser; End;//TIdSimpleUserManager //============================================================================= // * TIdUserManager * //============================================================================= const IdUserAccountDefaultAccess = 0;//guest type TIdUserManager = class; TIdUserAccount = class(TCollectionItem) protected FAttributes: TStrings; {$IFDEF USE_OBJECT_ARC} // When ARC is enabled, object references MUST be valid objects. // It is common for users to store non-object values, though, so // we will provide separate properties for those purposes // // TODO; use TValue instead of separating them // FDataObject: TObject; FDataValue: PtrInt; {$ELSE} FData: TObject; {$ENDIF} FUserName: string; FPassword: string; FRealName: string; FAccess: TIdUserAccess; // procedure SetAttributes(const AValue: TStrings); procedure SetPassword(const AValue: String); virtual; public constructor Create(ACollection: TCollection); override; destructor Destroy; override; // function CheckPassword(const APassword: String): Boolean; virtual; // {$IFDEF USE_OBJECT_ARC} property Data: TObject read FDataObject write FDataObject; property DataValue: PtrInt read FDataValue write FDataValue; {$ELSE} property Data: TObject read FData write FData; {$ENDIF} published property Access: TIdUserAccess read FAccess write FAccess default IdUserAccountDefaultAccess; property Attributes: TStrings read FAttributes write SetAttributes; property UserName: string read FUserName write FUserName; property Password: string read FPassword write SetPassword; property RealName: string read FRealName write FRealName; End;//TIdUserAccount TIdUserAccounts = class(TOwnedCollection) protected FCaseSensitiveUsernames: Boolean; FCaseSensitivePasswords: Boolean; // function GetAccount(const AIndex: Integer): TIdUserAccount; function GetByUsername(const AUsername: String): TIdUserAccount; procedure SetAccount(const AIndex: Integer; AAccountValue: TIdUserAccount); public function Add: TIdUserAccount; reintroduce; constructor Create(AOwner: TIdUserManager); // property CaseSensitiveUsernames: Boolean read FCaseSensitiveUsernames write FCaseSensitiveUsernames; property CaseSensitivePasswords: Boolean read FCaseSensitivePasswords write FCaseSensitivePasswords; property UserNames[const AUserName: String]: TIdUserAccount read GetByUsername; default; property Items[const AIndex: Integer]: TIdUserAccount read GetAccount write SetAccount; end;//TIdUserAccounts TIdUserManager = class(TIdCustomUserManager) protected FAccounts: TIdUserAccounts; // procedure DoAuthentication (const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); override; function GetOptions: TIdCustomUserManagerOptions; override; procedure SetAccounts(AValue: TIdUserAccounts); procedure SetOptions(const AValue: TIdCustomUserManagerOptions); override; procedure InitComponent; override; public destructor Destroy; override; published property Accounts: TIdUserAccounts read FAccounts write SetAccounts; property Options; // events property OnBeforeAuthentication; property OnAfterAuthentication; End;//TIdUserManager implementation uses SysUtils; { How add UserAccounts to your component: 1) property UserAccounts: TIdCustomUserManager read FUserAccounts write SetUserAccounts; 2) procedure SetUserAccounts(const AValue: TIdCustomUserManager); begin if FUserAccounts <> AValue then begin if Assigned(FUserAccounts) then begin FUserAccounts.RemoveFreeNotification(Self); end; FUserAccounts := AValue; if Assigned(FUserAccounts) then begin FUserAccounts.FreeNotification(Self); end; end; end; 3) procedure Notification(AComponent: TComponent; Operation: TOperation); begin ... if (Operation = opRemove) and (AComponent = FUserAccounts) then begin FUserAccounts := nil; end; ... inherited Notification(AComponent, Operation); end; 4) ... if Assigned(FUserAccounts) then begin FAuthenticated := FUserAccounts.AuthenticateUser(FUsername, ASender.UnparsedParams); if FAuthenticated then else } { TIdCustomUserManager } function TIdCustomUserManager.AuthenticateUser(const AUsername, APassword: String): Boolean; var LUserHandle: TIdUserHandle; Begin Result := IsRegisteredUser(AuthenticateUser(AUsername, APassword, LUserHandle)); LogoffUser(LUserHandle); End;//AuthenticateUser function TIdCustomUserManager.AuthenticateUser(const AUsername, APassword: String; var VUserHandle: TIdUserHandle): TIdUserAccess; var LPassword: String; Begin LPassword := APassword; VUserHandle := IdUserHandleNone; Result := IdUserAccessDenied; DoBeforeAuthentication(AUsername, LPassword, VUserHandle, Result); DoAuthentication(AUsername, LPassword, VUserHandle, Result); DoAfterAuthentication(AUsername, LPassword, VUserHandle, Result); End;// class function TIdCustomUserManager.IsRegisteredUser(AUserAccess: TIdUserAccess): Boolean; Begin Result := AUserAccess>=0; End; procedure TIdCustomUserManager.DoBeforeAuthentication(const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); Begin if Assigned(FOnBeforeAuthentication) then begin FOnBeforeAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess); end; End;// procedure TIdCustomUserManager.DoAfterAuthentication(const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); Begin if Assigned(FOnAfterAuthentication) then begin FOnAfterAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess); end; End;// function TIdCustomUserManager.GetOptions: TIdCustomUserManagerOptions; Begin Result := []; End;// procedure TIdCustomUserManager.SetOptions(const AValue: TIdCustomUserManagerOptions); Begin End; procedure TIdCustomUserManager.SetDomain(const AValue: String); begin if FDomain<>AValue then begin FDomain := AValue; end; end; procedure TIdCustomUserManager.LogoffUser(AUserHandle: TIdUserHandle); Begin DoLogoffUser(AUserHandle); End;//free resources, unallocate handles, etc... //============================================================================= procedure TIdCustomUserManager.DoLogoffUser(var VUserHandle: TIdUserHandle); Begin if Assigned(FOnLogoffUser) then begin FOnLogoffUser(SELF, VUserHandle); end; End;// function TIdCustomUserManager.ChallengeUser(var VIsSafe : Boolean; const AUserName: String): String; begin VIsSafe := True; Result := ''; end; procedure TIdCustomUserManager.UserDisconnected(const AUser: String); begin end; function TIdCustomUserManager.SendsChallange : Boolean; begin Result := False; end; { TIdUserAccount } function TIdUserAccount.CheckPassword(const APassword: String): Boolean; begin if (Collection as TIdUserAccounts).CaseSensitivePasswords then begin Result := Password = APassword; end else begin Result := TextIsSame(Password, APassword); end; end; constructor TIdUserAccount.Create(ACollection: TCollection); begin inherited Create(ACollection); FAttributes := TStringList.Create; FAccess := IdUserAccountDefaultAccess; end; destructor TIdUserAccount.Destroy; begin FreeAndNil(FAttributes); inherited Destroy; end; procedure TIdUserAccount.SetAttributes(const AValue: TStrings); begin FAttributes.Assign(AValue); end; procedure TIdUserAccount.SetPassword(const AValue: String); begin FPassword := AValue; end; { TIdUserAccounts } constructor TIdUserAccounts.Create(AOwner: TIdUserManager); begin inherited Create(AOwner, TIdUserAccount); end; function TIdUserAccounts.GetAccount(const AIndex: Integer): TIdUserAccount; begin Result := TIdUserAccount(inherited Items[AIndex]); end; function TIdUserAccounts.GetByUsername(const AUsername: String): TIdUserAccount; var i: Integer; begin Result := nil; if CaseSensitiveUsernames then begin for i := 0 to Count - 1 do begin if AUsername = Items[i].UserName then begin Result := Items[i]; Break; end; end; end else begin for i := 0 to Count - 1 do begin if TextIsSame(AUsername, Items[i].UserName) then begin Result := Items[i]; Break; end; end; end; end; procedure TIdUserAccounts.SetAccount(const AIndex: Integer; AAccountValue: TIdUserAccount); begin inherited SetItem(AIndex, AAccountValue); end; function TIdUserAccounts.Add: TIdUserAccount; begin Result := inherited Add as TIdUserAccount; end; { IdUserAccounts - Main Component } procedure TIdUserManager.InitComponent; begin inherited; FAccounts := TIdUserAccounts.Create(Self); end; destructor TIdUserManager.Destroy; begin FreeAndNil(FAccounts); inherited Destroy; end; procedure TIdUserManager.DoAuthentication(const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); var LUser: TIdUserAccount; begin VUserHandle := IdUserHandleNone; VUserAccess := IdUserAccessDenied; LUser := Accounts[AUsername]; if Assigned(LUser) then begin if LUser.CheckPassword(VPassword) then begin VUserHandle := LUser.ID; VUserAccess := LUser.Access; end; end; end; procedure TIdUserManager.SetAccounts(AValue: TIdUserAccounts); begin FAccounts.Assign(AValue); end; function TIdUserManager.GetOptions: TIdCustomUserManagerOptions; Begin Result := []; if FAccounts.CaseSensitiveUsernames then begin Include(Result, umoCaseSensitiveUsername); end; if FAccounts.CaseSensitivePasswords then begin Include(Result, umoCaseSensitivePassword); end; End;// procedure TIdUserManager.SetOptions(const AValue: TIdCustomUserManagerOptions); Begin FAccounts.CaseSensitiveUsernames := umoCaseSensitiveUsername in AValue; FAccounts.CaseSensitivePasswords := umoCaseSensitivePassword in AValue; End;// { TIdSimpleUserManager } procedure TIdSimpleUserManager.DoAuthentication(const AUsername: String; var VPassword: String; var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); Begin if Assigned(FOnAuthentication) then begin FOnAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess); end; End;// function TIdSimpleUserManager.GetOptions: TIdCustomUserManagerOptions; Begin Result := FOptions; End;// procedure TIdSimpleUserManager.SetOptions( const AValue: TIdCustomUserManagerOptions); Begin FOptions := AValue; End;// end.