IdUserAccounts.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.5 10/26/2004 10:51:40 PM JPMugaas
  18. Updated ref.
  19. Rev 1.4 7/6/2004 4:53:46 PM DSiders
  20. Corrected spelling of Challenge in properties, methods, types.
  21. Rev 1.3 2004.02.03 5:44:40 PM czhower
  22. Name changes
  23. Rev 1.2 2004.01.22 2:05:16 PM czhower
  24. TextIsSame
  25. Rev 1.1 1/21/2004 4:21:08 PM JPMugaas
  26. InitComponent
  27. Rev 1.0 11/13/2002 08:04:16 AM JPMugaas
  28. }
  29. unit IdUserAccounts;
  30. {
  31. Original Author: Sergio Perry
  32. Date: 24/04/2001
  33. 2002-05-03 - Andrew P.Rybin
  34. - TIdCustomUserManager,TIdSimpleUserManager,UserId
  35. - universal TIdUserManagerAuthenticationEvent> Sender: TObject
  36. }
  37. interface
  38. {$i IdCompilerDefines.inc}
  39. uses
  40. Classes,
  41. IdGlobal,
  42. IdBaseComponent,
  43. IdComponent;
  44. type
  45. TIdUserHandle = UInt32;//ptr,object,collection.item.id or THandle
  46. TIdUserAccess = Integer; //<0-denied, >=0-accept; ex: 0-guest,1-user,2-power user,3-admin
  47. var
  48. IdUserHandleNone: TIdUserHandle = High(UInt32)-1; //Special handle: empty handle
  49. IdUserHandleBroadcast: TIdUserHandle = High(UInt32); //Special handle
  50. IdUserAccessDenied: TIdUserAccess = Low(Integer); //Special access
  51. type
  52. TIdCustomUserManagerOption = (umoCaseSensitiveUsername, umoCaseSensitivePassword);
  53. TIdCustomUserManagerOptions = set of TIdCustomUserManagerOption;
  54. TIdUserManagerAuthenticationEvent = procedure(Sender: TObject; {TIdCustomUserManager, TIdPeerThread, etc}
  55. const AUsername: String;
  56. var VPassword: String;
  57. var VUserHandle: TIdUserHandle;
  58. var VUserAccess: TIdUserAccess) of object;
  59. TIdUserManagerLogoffEvent = procedure(Sender: TObject; var VUserHandle: TIdUserHandle) of object;
  60. TIdCustomUserManager = class(TIdBaseComponent)
  61. protected
  62. FDomain: String;
  63. FOnAfterAuthentication: TIdUserManagerAuthenticationEvent; //3
  64. FOnBeforeAuthentication: TIdUserManagerAuthenticationEvent;//1
  65. FOnLogoffUser: TIdUserManagerLogoffEvent;//4
  66. //
  67. procedure DoBeforeAuthentication(const AUsername: String; var VPassword: String;
  68. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual;
  69. // Descendants must override this method:
  70. procedure DoAuthentication (const AUsername: String; var VPassword: String;
  71. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual; abstract;
  72. procedure DoAfterAuthentication (const AUsername: String; var VPassword: String;
  73. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); virtual;
  74. procedure DoLogoffUser(var VUserHandle: TIdUserHandle); virtual;
  75. function GetOptions: TIdCustomUserManagerOptions; virtual;
  76. procedure SetDomain(const AValue: String); virtual;
  77. procedure SetOptions(const AValue: TIdCustomUserManagerOptions); virtual;
  78. // props
  79. property Domain: String read FDomain write SetDomain;
  80. property Options: TIdCustomUserManagerOptions read GetOptions write SetOptions;
  81. // events
  82. property OnBeforeAuthentication: TIdUserManagerAuthenticationEvent
  83. read FOnBeforeAuthentication write FOnBeforeAuthentication;
  84. property OnAfterAuthentication: TIdUserManagerAuthenticationEvent
  85. read FOnAfterAuthentication write FOnAfterAuthentication;
  86. property OnLogoffUser: TIdUserManagerLogoffEvent read FOnLogoffUser write FOnLogoffUser;
  87. public
  88. //Challenge user is a nice backdoor for some things we will do in a descendent class
  89. function ChallengeUser(var VIsSafe : Boolean; const AUserName : String) : String; virtual;
  90. function AuthenticateUser(const AUsername, APassword: String): Boolean; overload;
  91. function AuthenticateUser(const AUsername, APassword: String; var VUserHandle: TIdUserHandle): TIdUserAccess; overload;
  92. class function IsRegisteredUser(AUserAccess: TIdUserAccess): Boolean;
  93. procedure LogoffUser(AUserHandle: TIdUserHandle); virtual;
  94. procedure UserDisconnected(const AUser : String); virtual;
  95. function SendsChallange : Boolean; virtual;
  96. End;//TIdCustomUserManager
  97. //=============================================================================
  98. // * TIdSimpleUserManager *
  99. //=============================================================================
  100. TIdSimpleUserManager = class(TIdCustomUserManager)
  101. protected
  102. FOptions: TIdCustomUserManagerOptions;
  103. FOnAuthentication: TIdUserManagerAuthenticationEvent;
  104. //
  105. procedure DoAuthentication (const AUsername: String; var VPassword: String;
  106. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); override;
  107. function GetOptions: TIdCustomUserManagerOptions; override;
  108. procedure SetOptions(const AValue: TIdCustomUserManagerOptions); override;
  109. published
  110. property Domain;
  111. property Options;
  112. // events
  113. property OnBeforeAuthentication;
  114. property OnAuthentication: TIdUserManagerAuthenticationEvent read FOnAuthentication write FOnAuthentication;
  115. property OnAfterAuthentication;
  116. property OnLogoffUser;
  117. End;//TIdSimpleUserManager
  118. //=============================================================================
  119. // * TIdUserManager *
  120. //=============================================================================
  121. const
  122. IdUserAccountDefaultAccess = 0;//guest
  123. type
  124. TIdUserManager = class;
  125. TIdUserAccount = class(TCollectionItem)
  126. protected
  127. FAttributes: TStrings;
  128. {$IFDEF USE_OBJECT_ARC}
  129. // When ARC is enabled, object references MUST be valid objects.
  130. // It is common for users to store non-object values, though, so
  131. // we will provide separate properties for those purposes
  132. //
  133. // TODO; use TValue instead of separating them
  134. //
  135. FDataObject: TObject;
  136. FDataValue: PtrInt;
  137. {$ELSE}
  138. FData: TObject;
  139. {$ENDIF}
  140. FUserName: string;
  141. FPassword: string;
  142. FRealName: string;
  143. FAccess: TIdUserAccess;
  144. //
  145. procedure SetAttributes(const AValue: TStrings);
  146. procedure SetPassword(const AValue: String); virtual;
  147. public
  148. constructor Create(ACollection: TCollection); override;
  149. destructor Destroy; override;
  150. //
  151. function CheckPassword(const APassword: String): Boolean; virtual;
  152. //
  153. {$IFDEF USE_OBJECT_ARC}
  154. property DataObject: TObject read FDataObject write FDataObject;
  155. property DataValue: PtrInt read FDataValue write FDataValue;
  156. {$ELSE}
  157. property Data: TObject read FData write FData;
  158. {$ENDIF}
  159. published
  160. property Access: TIdUserAccess read FAccess write FAccess default IdUserAccountDefaultAccess;
  161. property Attributes: TStrings read FAttributes write SetAttributes;
  162. property UserName: string read FUserName write FUserName;
  163. property Password: string read FPassword write SetPassword;
  164. property RealName: string read FRealName write FRealName;
  165. End;//TIdUserAccount
  166. TIdUserAccounts = class(TOwnedCollection)
  167. protected
  168. FCaseSensitiveUsernames: Boolean;
  169. FCaseSensitivePasswords: Boolean;
  170. //
  171. function GetAccount(const AIndex: Integer): TIdUserAccount;
  172. function GetByUsername(const AUsername: String): TIdUserAccount;
  173. procedure SetAccount(const AIndex: Integer; AAccountValue: TIdUserAccount);
  174. public
  175. function Add: TIdUserAccount; reintroduce;
  176. constructor Create(AOwner: TIdUserManager);
  177. //
  178. property CaseSensitiveUsernames: Boolean read FCaseSensitiveUsernames
  179. write FCaseSensitiveUsernames;
  180. property CaseSensitivePasswords: Boolean read FCaseSensitivePasswords
  181. write FCaseSensitivePasswords;
  182. property UserNames[const AUserName: String]: TIdUserAccount read GetByUsername; default;
  183. property Items[const AIndex: Integer]: TIdUserAccount read GetAccount write SetAccount;
  184. end;//TIdUserAccounts
  185. TIdUserManager = class(TIdCustomUserManager)
  186. protected
  187. FAccounts: TIdUserAccounts;
  188. //
  189. procedure DoAuthentication (const AUsername: String; var VPassword: String;
  190. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess); override;
  191. function GetOptions: TIdCustomUserManagerOptions; override;
  192. procedure SetAccounts(AValue: TIdUserAccounts);
  193. procedure SetOptions(const AValue: TIdCustomUserManagerOptions); override;
  194. procedure InitComponent; override;
  195. public
  196. destructor Destroy; override;
  197. published
  198. property Accounts: TIdUserAccounts read FAccounts write SetAccounts;
  199. property Options;
  200. // events
  201. property OnBeforeAuthentication;
  202. property OnAfterAuthentication;
  203. End;//TIdUserManager
  204. implementation
  205. uses
  206. SysUtils;
  207. { How add UserAccounts to your component:
  208. 1) property UserAccounts: TIdCustomUserManager read FUserAccounts write SetUserAccounts;
  209. 2) procedure SetUserAccounts(const AValue: TIdCustomUserManager);
  210. begin
  211. if FUserAccounts <> AValue then begin
  212. if Assigned(FUserAccounts) then begin
  213. FUserAccounts.RemoveFreeNotification(Self);
  214. end;
  215. FUserAccounts := AValue;
  216. if Assigned(FUserAccounts) then begin
  217. FUserAccounts.FreeNotification(Self);
  218. end;
  219. end;
  220. end;
  221. 3) procedure Notification(AComponent: TComponent; Operation: TOperation);
  222. begin
  223. ...
  224. if (Operation = opRemove) and (AComponent = FUserAccounts) then begin
  225. FUserAccounts := nil;
  226. end;
  227. ...
  228. inherited Notification(AComponent, Operation);
  229. end;
  230. 4) ... if Assigned(FUserAccounts) then begin
  231. FAuthenticated := FUserAccounts.AuthenticateUser(FUsername, ASender.UnparsedParams);
  232. if FAuthenticated then else
  233. }
  234. { TIdCustomUserManager }
  235. function TIdCustomUserManager.AuthenticateUser(const AUsername, APassword: String): Boolean;
  236. var
  237. LUserHandle: TIdUserHandle;
  238. Begin
  239. Result := IsRegisteredUser(AuthenticateUser(AUsername, APassword, LUserHandle));
  240. LogoffUser(LUserHandle);
  241. End;//AuthenticateUser
  242. function TIdCustomUserManager.AuthenticateUser(const AUsername, APassword: String; var VUserHandle: TIdUserHandle): TIdUserAccess;
  243. var
  244. LPassword: String;
  245. Begin
  246. LPassword := APassword;
  247. VUserHandle := IdUserHandleNone;
  248. Result := IdUserAccessDenied;
  249. DoBeforeAuthentication(AUsername, LPassword, VUserHandle, Result);
  250. DoAuthentication(AUsername, LPassword, VUserHandle, Result);
  251. DoAfterAuthentication(AUsername, LPassword, VUserHandle, Result);
  252. End;//
  253. class function TIdCustomUserManager.IsRegisteredUser(AUserAccess: TIdUserAccess): Boolean;
  254. Begin
  255. Result := AUserAccess>=0;
  256. End;
  257. procedure TIdCustomUserManager.DoBeforeAuthentication(const AUsername: String; var VPassword: String;
  258. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess);
  259. Begin
  260. if Assigned(FOnBeforeAuthentication) then begin
  261. FOnBeforeAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess);
  262. end;
  263. End;//
  264. procedure TIdCustomUserManager.DoAfterAuthentication(const AUsername: String; var VPassword: String;
  265. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess);
  266. Begin
  267. if Assigned(FOnAfterAuthentication) then begin
  268. FOnAfterAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess);
  269. end;
  270. End;//
  271. function TIdCustomUserManager.GetOptions: TIdCustomUserManagerOptions;
  272. Begin
  273. Result := [];
  274. End;//
  275. procedure TIdCustomUserManager.SetOptions(const AValue: TIdCustomUserManagerOptions);
  276. Begin
  277. End;
  278. procedure TIdCustomUserManager.SetDomain(const AValue: String);
  279. begin
  280. if FDomain<>AValue then begin
  281. FDomain := AValue;
  282. end;
  283. end;
  284. procedure TIdCustomUserManager.LogoffUser(AUserHandle: TIdUserHandle);
  285. Begin
  286. DoLogoffUser(AUserHandle);
  287. End;//free resources, unallocate handles, etc...
  288. //=============================================================================
  289. procedure TIdCustomUserManager.DoLogoffUser(var VUserHandle: TIdUserHandle);
  290. Begin
  291. if Assigned(FOnLogoffUser) then begin
  292. FOnLogoffUser(SELF, VUserHandle);
  293. end;
  294. End;//
  295. function TIdCustomUserManager.ChallengeUser(var VIsSafe : Boolean;
  296. const AUserName: String): String;
  297. begin
  298. VIsSafe := True;
  299. Result := '';
  300. end;
  301. procedure TIdCustomUserManager.UserDisconnected(const AUser: String);
  302. begin
  303. end;
  304. function TIdCustomUserManager.SendsChallange : Boolean;
  305. begin
  306. Result := False;
  307. end;
  308. { TIdUserAccount }
  309. function TIdUserAccount.CheckPassword(const APassword: String): Boolean;
  310. begin
  311. if (Collection as TIdUserAccounts).CaseSensitivePasswords then begin
  312. Result := Password = APassword;
  313. end else begin
  314. Result := TextIsSame(Password, APassword);
  315. end;
  316. end;
  317. constructor TIdUserAccount.Create(ACollection: TCollection);
  318. begin
  319. inherited Create(ACollection);
  320. FAttributes := TStringList.Create;
  321. FAccess := IdUserAccountDefaultAccess;
  322. end;
  323. destructor TIdUserAccount.Destroy;
  324. begin
  325. FreeAndNil(FAttributes);
  326. inherited Destroy;
  327. end;
  328. procedure TIdUserAccount.SetAttributes(const AValue: TStrings);
  329. begin
  330. FAttributes.Assign(AValue);
  331. end;
  332. procedure TIdUserAccount.SetPassword(const AValue: String);
  333. begin
  334. FPassword := AValue;
  335. end;
  336. { TIdUserAccounts }
  337. constructor TIdUserAccounts.Create(AOwner: TIdUserManager);
  338. begin
  339. inherited Create(AOwner, TIdUserAccount);
  340. end;
  341. function TIdUserAccounts.GetAccount(const AIndex: Integer): TIdUserAccount;
  342. begin
  343. Result := TIdUserAccount(inherited Items[AIndex]);
  344. end;
  345. function TIdUserAccounts.GetByUsername(const AUsername: String): TIdUserAccount;
  346. var
  347. i: Integer;
  348. begin
  349. Result := nil;
  350. if CaseSensitiveUsernames then begin
  351. for i := 0 to Count - 1 do begin
  352. if AUsername = Items[i].UserName then begin
  353. Result := Items[i];
  354. Break;
  355. end;
  356. end;
  357. end
  358. else begin
  359. for i := 0 to Count - 1 do begin
  360. if TextIsSame(AUsername, Items[i].UserName) then begin
  361. Result := Items[i];
  362. Break;
  363. end;
  364. end;
  365. end;
  366. end;
  367. procedure TIdUserAccounts.SetAccount(const AIndex: Integer; AAccountValue: TIdUserAccount);
  368. begin
  369. inherited SetItem(AIndex, AAccountValue);
  370. end;
  371. function TIdUserAccounts.Add: TIdUserAccount;
  372. begin
  373. Result := inherited Add as TIdUserAccount;
  374. end;
  375. { IdUserAccounts - Main Component }
  376. procedure TIdUserManager.InitComponent;
  377. begin
  378. inherited;
  379. FAccounts := TIdUserAccounts.Create(Self);
  380. end;
  381. destructor TIdUserManager.Destroy;
  382. begin
  383. FreeAndNil(FAccounts);
  384. inherited Destroy;
  385. end;
  386. procedure TIdUserManager.DoAuthentication(const AUsername: String; var VPassword: String;
  387. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess);
  388. var
  389. LUser: TIdUserAccount;
  390. begin
  391. VUserHandle := IdUserHandleNone;
  392. VUserAccess := IdUserAccessDenied;
  393. LUser := Accounts[AUsername];
  394. if Assigned(LUser) then begin
  395. if LUser.CheckPassword(VPassword) then begin
  396. VUserHandle := LUser.ID;
  397. VUserAccess := LUser.Access;
  398. end;
  399. end;
  400. end;
  401. procedure TIdUserManager.SetAccounts(AValue: TIdUserAccounts);
  402. begin
  403. FAccounts.Assign(AValue);
  404. end;
  405. function TIdUserManager.GetOptions: TIdCustomUserManagerOptions;
  406. Begin
  407. Result := [];
  408. if FAccounts.CaseSensitiveUsernames then begin
  409. Include(Result, umoCaseSensitiveUsername);
  410. end;
  411. if FAccounts.CaseSensitivePasswords then begin
  412. Include(Result, umoCaseSensitivePassword);
  413. end;
  414. End;//
  415. procedure TIdUserManager.SetOptions(const AValue: TIdCustomUserManagerOptions);
  416. Begin
  417. FAccounts.CaseSensitiveUsernames := umoCaseSensitiveUsername in AValue;
  418. FAccounts.CaseSensitivePasswords := umoCaseSensitivePassword in AValue;
  419. End;//
  420. { TIdSimpleUserManager }
  421. procedure TIdSimpleUserManager.DoAuthentication(const AUsername: String; var VPassword: String;
  422. var VUserHandle: TIdUserHandle; var VUserAccess: TIdUserAccess);
  423. Begin
  424. if Assigned(FOnAuthentication) then begin
  425. FOnAuthentication(SELF,AUsername,VPassword,VUserHandle,VUserAccess);
  426. end;
  427. End;//
  428. function TIdSimpleUserManager.GetOptions: TIdCustomUserManagerOptions;
  429. Begin
  430. Result := FOptions;
  431. End;//
  432. procedure TIdSimpleUserManager.SetOptions(
  433. const AValue: TIdCustomUserManagerOptions);
  434. Begin
  435. FOptions := AValue;
  436. End;//
  437. end.