diff --git a/demo/tutorial12/AuthFilter.pas b/demo/tutorial12/AuthFilter.pas new file mode 100644 index 00000000..8804dae8 --- /dev/null +++ b/demo/tutorial12/AuthFilter.pas @@ -0,0 +1,102 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +unit AuthFilter; + +// note: this is unsupported example code + +interface + +uses + djWebFilter, + djServerContext, + djTypes, + djInterfaces, + Classes, SysUtils; + +type + + { TAuthFilter } + + TAuthFilter = class(TdjWebFilter) + private + AuthorizeEndpoint: string; + ClientID: string; + RedirectURI: string; + public + procedure Init(const Config: IWebFilterConfig); override; + procedure DoFilter(Context: TdjServerContext; Request: TdjRequest; + Response: TdjResponse; const Chain: IWebFilterChain); override; + end; + +implementation + +function CreateGUIDString: string; +var + Guid: TGUID; +begin + CreateGUID(Guid); + Result := GUIDToString(Guid); +end; + +{ TAuthFilter } + +procedure TAuthFilter.Init(const Config: IWebFilterConfig); +begin + AuthorizeEndpoint := Config.GetInitParameter('AuthorizeEndpoint'); + ClientID := Config.GetInitParameter('ClientID'); + RedirectURI := Config.GetInitParameter('RedirectURI'); +end; + +procedure TAuthFilter.DoFilter(Context: TdjServerContext; Request: TdjRequest; + Response: TdjResponse; const Chain: IWebFilterChain); +var + AccessToken: string; + State: string; +begin + AccessToken := Request.Session.Content.Values['access_token']; + if AccessToken = '' then + begin + State := CreateGUIDString; + Response.Session.Content.Values['state'] := State; + Response.Redirect(AuthorizeEndpoint + + '?client_id=' + ClientID // Your app registration's Application (client) ID + + '&response_type=token' // Requests an access token + + '&redirect_uri=' + RedirectURI + + '&scope=User.Read Mail.Send' // Request read profile and send mail permission + + '&response_mode=form_post' + + '&state=' + State + ); + end + else + begin + Chain.DoFilter(Context, Request, Response); // pass + end; +end; + +end. diff --git a/demo/tutorial12/AuthResponseResource.pas b/demo/tutorial12/AuthResponseResource.pas new file mode 100644 index 00000000..97760fb6 --- /dev/null +++ b/demo/tutorial12/AuthResponseResource.pas @@ -0,0 +1,79 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +unit AuthResponseResource; + +// note: this is unsupported example code + +interface + +uses + djWebComponent, djTypes; + +type + + { TAuthResponseResource } + + TAuthResponseResource = class(TdjWebComponent) + public + procedure OnPost(Request: TdjRequest; Response: TdjResponse); override; + end; + +implementation + +uses + SysUtils; + +{ TAuthResponseResource } + +procedure TAuthResponseResource.OnPost(Request: TdjRequest; Response: TdjResponse); +var + AccessToken: string; + // P: string; +begin + if Request.Params.Values['state'] <> Request.Session.Content.Values['state'] then + begin + Response.ResponseNo := 401; + WriteLn('Invalid state parameter.'); + Exit; + end; + + // for P in Request.Params do + // begin + // WriteLn(P); + // end; + + // Read the access_token + AccessToken := Request.Params.Values['access_token']; + + Response.Session.Content.Values['access_token'] := AccessToken; + Response.Redirect('/index.html'); +end; + +end. + diff --git a/demo/tutorial12/MainUnit.pas b/demo/tutorial12/MainUnit.pas new file mode 100644 index 00000000..cb4af855 --- /dev/null +++ b/demo/tutorial12/MainUnit.pas @@ -0,0 +1,89 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +unit MainUnit; + +// note: this is unsupported example code + +interface + +procedure Demo; + +implementation + +uses + AuthFilter, + AuthResponseResource, + RootResource, + djServer, djWebAppContext, djNCSALogFilter, djWebFilterHolder, + ShellAPI, SysUtils; + +procedure Demo; +const + AUTHORIZE_ENDPOINT = 'https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize'; + // Application (client) ID from Entra configuration + CLIENT_ID = 'ee5a0402-2861-44a2-b0e1-d79bfafbe56a'; + // Redirect URI must match Entra configuration + REDIRECT_PATH = '/auth-response'; + REDIRECT_URI = 'http://localhost' + REDIRECT_PATH; +var + Context: TdjWebAppContext; + FilterHolder: TdjWebFilterHolder; + Server: TdjServer; +begin + FilterHolder := TdjWebFilterHolder.Create(TAuthFilter); + FilterHolder.SetInitParameter('AuthorizeEndpoint', AUTHORIZE_ENDPOINT); + FilterHolder.SetInitParameter('ClientID', CLIENT_ID); + FilterHolder.SetInitParameter('RedirectURI', REDIRECT_URI); + + Context := TdjWebAppContext.Create('', True); + Context.AddWebComponent(TRootResource, '/index.html'); + Context.AddWebComponent(TAuthResponseResource, REDIRECT_PATH); + Context.AddWebFilter(FilterHolder, '*.html'); + Context.AddFilterWithMapping(TdjNCSALogFilter, '/*'); + + Server := TdjServer.Create(80); + try + try + Server.Add(Context); + Server.Start; + + ShellExecute(0, 'open', PChar('http://localhost/index.html'), '', '', 0); + + WriteLn('Server is running, launching web browser ...'); + WriteLn('Hit any key to terminate.'); + except + on E: Exception do WriteLn(E.Message); + end; + ReadLn; + finally + Server.Free; + end; +end; + +end. diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.dpr b/demo/tutorial12/ReadUserProfileFromMSGraph.dpr new file mode 100644 index 00000000..63575731 --- /dev/null +++ b/demo/tutorial12/ReadUserProfileFromMSGraph.dpr @@ -0,0 +1,41 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +program ReadUserProfileFromMSGraph; + +// note: this is unsupported example code + +{$APPTYPE CONSOLE} + +uses + MainUnit; + +begin + Demo; +end. + diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.lpi b/demo/tutorial12/ReadUserProfileFromMSGraph.lpi new file mode 100644 index 00000000..057794ef --- /dev/null +++ b/demo/tutorial12/ReadUserProfileFromMSGraph.lpi @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="LCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="ReadUserProfileFromMSGraph.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="ReadUserProfileFromMSGraph"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + <Item> + <Name Value="EBTStompClientNotConnectedError"/> + </Item> + <Item> + <Name Value="ESynapseError"/> + </Item> + <Item> + <Name Value="EAssertionFailedError"/> + </Item> + <Item> + <Name Value="EIdReadTimeout"/> + </Item> + <Item> + <Name Value="EConnectionFailedException"/> + </Item> + <Item> + <Name Value="Exception"/> + </Item> + <Item> + <Name Value="EIgnoredTest"/> + </Item> + <Item> + <Name Value="EBTStompServerErrorMessage"/> + </Item> + <Item> + <Name Value="EBTStompServerHeartbeatMissing"/> + </Item> + <Item> + <Name Value="EJMSException"/> + </Item> + <Item> + <Name Value="EBTStompError"/> + </Item> + <Item> + <Name Value="EIdSocketError"/> + </Item> + <Item> + <Name Value="EIdConnClosedGracefully"/> + </Item> + <Item> + <Name Value="EConvertError"/> + </Item> + <Item> + <Name Value="EIllegalStateException"/> + </Item> + <Item> + <Name Value="EIllegalArgumentException"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.lpr b/demo/tutorial12/ReadUserProfileFromMSGraph.lpr new file mode 100644 index 00000000..63575731 --- /dev/null +++ b/demo/tutorial12/ReadUserProfileFromMSGraph.lpr @@ -0,0 +1,41 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +program ReadUserProfileFromMSGraph; + +// note: this is unsupported example code + +{$APPTYPE CONSOLE} + +uses + MainUnit; + +begin + Demo; +end. + diff --git a/demo/tutorial12/RootResource.pas b/demo/tutorial12/RootResource.pas new file mode 100644 index 00000000..81c85d55 --- /dev/null +++ b/demo/tutorial12/RootResource.pas @@ -0,0 +1,161 @@ +(* + + Daraja HTTP Framework + Copyright (C) Michael Justin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the Daraja framework without + disclosing the source code of your own applications. These activities + include: offering paid services to customers as an ASP, shipping Daraja + with a closed source product. + +*) + +unit RootResource; + +// note: this is unsupported example code + +interface + +uses + djWebComponent, djTypes; + +type + + { TRootResource } + + TRootResource = class(TdjWebComponent) + private + function ReadUserProfile(const AccessToken: string): string; + function SendMail(const AccessToken: string): string; + public + procedure OnGet(Request: TdjRequest; Response: TdjResponse); override; + end; + +implementation + +uses + {$IFDEF FPC}{$NOTES OFF}{$ENDIF}{$HINTS OFF}{$WARNINGS OFF} + IdHTTP, IdSSLOpenSSL, IdSSLOpenSSLHeaders, + {$IFDEF FPC}{$ELSE}{$HINTS ON}{$WARNINGS ON}{$ENDIF} + SysUtils, Classes; + +function CreateIdHTTPwithSSL12(const AccessToken: string): TIdHTTP; +var + IOHandler: TIdSSLIOHandlerSocketOpenSSL; +begin + Result := TIdHTTP.Create; + + IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Result); + IOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2]; + Result.IOHandler := IOHandler; + + Result.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + AccessToken; +end; + +{ TRootResource } + +procedure TRootResource.OnGet(Request: TdjRequest; Response: TdjResponse); +var + AccessToken: string; + APIResponse: string; +begin + AccessToken := Request.Session.Content.Values['access_token']; + + APIResponse := ReadUserProfile(AccessToken); + + SendMail(AccessToken); + + Response.ContentText := Format('<html><body><h1>Graph API example</h1>' + + '<h2>Signed-in user profile:</h2><p>%s</p>' + + '<h2>Send email:</h2><p>Email has been sent.</p></body></html>', + [APIResponse]); + Response.ContentType := 'text/html'; + Response.CharSet := 'utf-8'; +end; + +function TRootResource.ReadUserProfile(const AccessToken: string): string; +var + HTTP: TIdHTTP; +begin + HTTP := CreateIdHTTPwithSSL12(AccessToken); + try + try + Result := HTTP.Get('https://graph.microsoft.com/v1.0/users/me'); + except + WriteLn(IdSSLOpenSSLHeaders.WhichFailedToLoad); + raise; + end; + finally + HTTP.Free; + end; +end; + +function TRootResource.SendMail(const AccessToken: string): string; +const + JSON = + '{'+ #10 + +' "message": {'+ #10 + +' "subject": "Meet for lunch?",'+ #10 + +' "body": {'+ #10 + +' "contentType": "Text",'+ #10 + +' "content": "The new cafeteria is open."'+ #10 + +' },'+ #10 + +' "toRecipients": ['+ #10 + +' {'+ #10 + +' "emailAddress": {'+ #10 + +' "address": "info@habarisoft.com"'+ #10 + +' }'+ #10 + +' }'+ #10 + +' ]'+ #10 + +' },'+ #10 + +' "saveToSentItems": "false"'+ #10 + +'}'; +var + HTTP: TIdHTTP; + RequestBody: TStream; + ResponseBody: string; +begin + // WriteLn(JSON); + + HTTP := CreateIdHTTPwithSSL12(AccessToken); + try + try + HTTP.Request.ContentType := 'application/json'; + RequestBody := TStringStream.Create(JSON, TEncoding.UTF8); + ResponseBody := HTTP.Post('https://graph.microsoft.com/v1.0/me/sendMail', RequestBody); + // WriteLn('Response: "' + ResponseBody + '"'); + except + on E: EIdHTTPProtocolException do + begin + WriteLn(E.Message); + WriteLn(E.ErrorMessage); + raise; + end; + on E: Exception do + begin + WriteLn(E.Message); + raise; + end; + end; + finally + HTTP.Free; + end; +end; + +end.