IdSASLOAuth.pas 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. unit IdSASLOAuth;
  17. interface
  18. {$i IdCompilerDefines.inc}
  19. uses
  20. IdGlobal,
  21. IdSASL,
  22. IdSASLUserPass;
  23. type
  24. TIdSASLOAuth2BearerTokenEvent = procedure(Sender: TObject; var AccessToken: String) of object;
  25. {
  26. Implements RFC 7628
  27. A Set of Simple Authentication and Security Layer (SASL) Mechanisms for OAuth
  28. }
  29. TIdSASLOAuth2Base = class(TIdSASLUserPass)
  30. protected
  31. FOnGetAccessToken: TIdSASLOAuth2BearerTokenEvent;
  32. function DoStartAuthenticate(const AHost: string; const APort: TIdPort; const AAccessToken: string): String; virtual; abstract;
  33. function DoContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort): String; virtual; abstract;
  34. public
  35. function TryStartAuthenticate(const AHost: string; const APort: TIdPort; const AProtocolName : string; var VInitialResponse: String): Boolean; override;
  36. function StartAuthenticate(const AChallenge, AHost: string; const APort: TIdPort; const AProtocolName : string) : String; override;
  37. function ContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort; const AProtocolName : String): String; override;
  38. function IsReadyToStart: Boolean; override;
  39. published
  40. property OnGetAccessToken: TIdSASLOAuth2BearerTokenEvent read FOnGetAccessToken write FOnGetAccessToken;
  41. end;
  42. TIdSASLOAuth2Bearer = class(TIdSASLOAuth2Base)
  43. protected
  44. function DoStartAuthenticate(const AHost: string; const APort: TIdPort; const AAccessToken: string): String; override;
  45. function DoContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort): String; override;
  46. public
  47. class function ServiceName: TIdSASLServiceName; override;
  48. end;
  49. TIdSASLOAuth10ATokenEvent = procedure(Sender: TObject; var ARealm, AConsumerKey, AAccessToken, ASignatureMethod, ATimestamp, ANonce, ASignature: String) of object;
  50. TIdSASLOAuth10A = class(TIdSASLUserPass)
  51. protected
  52. FOnGetAccessToken: TIdSASLOAuth10ATokenEvent;
  53. public
  54. class function ServiceName: TIdSASLServiceName; override;
  55. function TryStartAuthenticate(const AHost: string; const APort: TIdPort; const AProtocolName : string; var VInitialResponse: String): Boolean; override;
  56. function StartAuthenticate(const AChallenge, AHost: string; const APort: TIdPort; const AProtocolName : string) : String; override;
  57. function ContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort; const AProtocolName : String): String; override;
  58. function IsReadyToStart: Boolean; override;
  59. published
  60. property OnGetAccessToken: TIdSASLOAuth10ATokenEvent read FOnGetAccessToken write FOnGetAccessToken;
  61. end;
  62. {
  63. Implements Google's XOAUTH2 extension
  64. }
  65. TIdSASLXOAuth2 = class(TIdSASLOAuth2Base)
  66. protected
  67. function DoStartAuthenticate(const AHost: string; const APort: TIdPort; const AAccessToken: string): String; override;
  68. function DoContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort): String; override;
  69. public
  70. class function ServiceName: TIdSASLServiceName; override;
  71. end;
  72. implementation
  73. uses
  74. SysUtils;
  75. { TIdSASLOAuth2BearerBase }
  76. function TIdSASLOAuth2Base.TryStartAuthenticate(const AHost: string; const APort: TIdPort; const AProtocolName : string; var VInitialResponse: String): Boolean;
  77. var
  78. LToken: String;
  79. begin
  80. LToken := GetPassword;
  81. if (LToken = '') and Assigned(FOnGetAccessToken) then begin
  82. FOnGetAccessToken(Self, LToken);
  83. end;
  84. VInitialResponse := DoStartAuthenticate(AHost, APort, LToken);
  85. Result := True;
  86. end;
  87. function TIdSASLOAuth2Base.StartAuthenticate(const AChallenge, AHost: string; const APort: TIdPort; const AProtocolName : string) : String;
  88. begin
  89. TryStartAuthenticate(AHost, APort, AProtocolName, Result);
  90. end;
  91. function TIdSASLOAuth2Base.ContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort; const AProtocolName : String): String;
  92. begin
  93. // TODO: parse response JSON for 'status', 'scope', and 'openid-configuration' values...
  94. Result := DoContinueAuthenticate(ALastResponse, AHost, APort);
  95. end;
  96. function TIdSASLOAuth2Base.IsReadyToStart: Boolean;
  97. begin
  98. Result := (GetUsername <> '') and ((GetPassword <> '') or Assigned(FOnGetAccessToken));
  99. end;
  100. { TIdSASLOAuthBearer }
  101. class function TIdSASLOAuth2Bearer.ServiceName: TIdSASLServiceName;
  102. begin
  103. Result := 'OAUTHBEARER'; {do not localize}
  104. end;
  105. function TIdSASLOAuth2Bearer.DoStartAuthenticate(const AHost: string; const APort: TIdPort; const AAccessToken: string): String;
  106. begin
  107. Result := Format('n,a=%s,'#1'host=%s'#1'port=%d'#1'auth=Bearer %s'#1#1, [GetUserName(), AHost, APort, AAccessToken]);
  108. end;
  109. function TIdSASLOAuth2Bearer.DoContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort): String;
  110. begin
  111. Result := #1;
  112. end;
  113. { TIdSASLOAuth10A }
  114. class function TIdSASLOAuth10A.ServiceName: TIdSASLServiceName;
  115. begin
  116. Result := 'OAUTH10A'; {do not localize}
  117. end;
  118. function TIdSASLOAuth10A.TryStartAuthenticate(const AHost: string; const APort: TIdPort; const AProtocolName : string;
  119. var VInitialResponse: String): Boolean;
  120. var
  121. LRealm, LKey, LToken, LMethod, LTimestamp, LNonce, LSignature: string;
  122. begin
  123. // TODO: add properties for these values...
  124. if Assigned(FOnGetAccessToken) then begin
  125. FOnGetAccessToken(Self, LRealm, LKey, LToken, LMethod, LTimestamp, LNonce, LSignature);
  126. end;
  127. VInitialResponse := Format(
  128. 'n,a=%s,'#1'host=%s'#1'port=%d'#1'auth=OAuth realm="%s",oauth_consumer_key="%s",oauth_token="%s",oauth_signature_method="%s",oauth_timestamp="%s",oauth_nonce="%s",oauth_signature="%s"'#1#1, {do not localize}
  129. [GetUsername, AHost, APort, LRealm, LKey, LToken, LMethod, LTimestamp, LNonce, LSignature]
  130. );
  131. Result := True;
  132. end;
  133. function TIdSASLOAuth10A.StartAuthenticate(const AChallenge, AHost: string; const APort: TIdPort; const AProtocolName : string) : String;
  134. begin
  135. TryStartAuthenticate(AHost, APort, AProtocolName, Result);
  136. end;
  137. function TIdSASLOAuth10A.ContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort; const AProtocolName : String): String;
  138. begin
  139. // TODO: parse response JSON for 'status', 'scope', and 'openid-configuration' values...
  140. Result := #1;
  141. end;
  142. function TIdSASLOAuth10A.IsReadyToStart: Boolean;
  143. begin
  144. Result := (GetUsername <> '') and Assigned(FOnGetAccessToken);
  145. end;
  146. { TIdSASLXOAuth2 }
  147. class function TIdSASLXOAuth2.ServiceName: TIdSASLServiceName;
  148. begin
  149. Result := 'XOAUTH2'; {do not localize}
  150. end;
  151. function TIdSASLXOAuth2.DoStartAuthenticate(const AHost: string; const APort: TIdPort; const AAccessToken : string): String;
  152. begin
  153. Result := Format('user=%s'#1'auth=Bearer %s'#1#1, [GetUsername, AAccessToken]); {do not localize}
  154. end;
  155. function TIdSASLXOAuth2.DoContinueAuthenticate(const ALastResponse, AHost: string; const APort: TIdPort): String;
  156. begin
  157. Result := '';
  158. end;
  159. end.