2016-06-22 17:49:16 +02:00
|
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Delphi MVC Framework
|
|
|
|
|
//
|
2017-01-05 12:44:34 +01:00
|
|
|
|
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
|
2016-06-22 17:49:16 +02:00
|
|
|
|
//
|
|
|
|
|
// https://github.com/danieleteti/delphimvcframework
|
|
|
|
|
//
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
//
|
|
|
|
|
// *************************************************************************** }
|
2015-12-22 12:38:17 +01:00
|
|
|
|
|
2015-04-01 17:01:23 +02:00
|
|
|
|
unit MVCFramework.Middleware.Authentication;
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
2016-12-30 20:41:55 +01:00
|
|
|
|
{$I dmvcframework.inc}
|
|
|
|
|
|
|
|
|
|
|
2015-04-01 17:01:23 +02:00
|
|
|
|
uses
|
2016-09-16 23:54:54 +02:00
|
|
|
|
MVCFramework, MVCFramework.Logger,
|
|
|
|
|
System.Generics.Collections, MVCFramework.Commons;
|
2015-04-01 17:01:23 +02:00
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
TMVCBasicAuthenticationMiddleware = class(TInterfacedObject, IMVCMiddleware)
|
|
|
|
|
strict private
|
|
|
|
|
FMVCAuthenticationHandler: IMVCAuthenticationHandler;
|
|
|
|
|
protected
|
|
|
|
|
FRealm: string;
|
|
|
|
|
procedure OnBeforeRouting(Context: TWebContext; var Handled: Boolean);
|
2016-02-23 22:33:21 +01:00
|
|
|
|
procedure OnAfterControllerAction(Context: TWebContext;
|
|
|
|
|
const AActionName: string; const Handled: Boolean);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
procedure OnBeforeControllerAction(Context: TWebContext;
|
2016-02-23 22:33:21 +01:00
|
|
|
|
const AControllerQualifiedClassName: string; const AActionName: string;
|
|
|
|
|
var Handled: Boolean);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
public
|
|
|
|
|
constructor Create(AMVCAuthenticationHandler: IMVCAuthenticationHandler;
|
|
|
|
|
Realm: string = 'DelphiMVCFramework REALM'); virtual;
|
|
|
|
|
end;
|
|
|
|
|
|
2016-09-16 23:54:54 +02:00
|
|
|
|
TMVCCustomAuthenticationMiddleware = class(TInterfacedObject, IMVCMiddleware)
|
|
|
|
|
strict private
|
|
|
|
|
FMVCAuthenticationHandler: IMVCAuthenticationHandler;
|
|
|
|
|
private
|
|
|
|
|
FLoginUrl: string;
|
|
|
|
|
procedure SendResponse(const Context: TWebContext; var Handled: Boolean;
|
|
|
|
|
HTTPStatus: Word = HTTP_STATUS.Unauthorized);
|
|
|
|
|
protected
|
|
|
|
|
procedure OnBeforeRouting(Context: TWebContext; var Handled: Boolean);
|
|
|
|
|
procedure OnAfterControllerAction(Context: TWebContext;
|
|
|
|
|
const AActionName: string; const Handled: Boolean);
|
|
|
|
|
procedure OnBeforeControllerAction(Context: TWebContext;
|
|
|
|
|
const AControllerQualifiedClassName: string; const AActionName: string;
|
|
|
|
|
var Handled: Boolean);
|
2016-09-18 19:19:23 +02:00
|
|
|
|
procedure DoLogin(Context: TWebContext; var Handled: Boolean);
|
|
|
|
|
procedure DoLogout(Context: TWebContext; var Handled: Boolean);
|
2016-09-16 23:54:54 +02:00
|
|
|
|
public
|
|
|
|
|
constructor Create(
|
|
|
|
|
AMVCAuthenticationHandler: IMVCAuthenticationHandler;
|
2016-09-18 19:19:23 +02:00
|
|
|
|
aLoginUrl: string = '/system/users/logged'
|
2016-09-16 23:54:54 +02:00
|
|
|
|
); virtual;
|
|
|
|
|
end;
|
|
|
|
|
|
2015-04-01 17:01:23 +02:00
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
uses
|
2017-02-22 19:50:37 +01:00
|
|
|
|
System.SysUtils
|
|
|
|
|
, MVCFramework.Session
|
|
|
|
|
, ObjectsMappers
|
|
|
|
|
, System.StrUtils
|
|
|
|
|
, System.Classes
|
|
|
|
|
, MVCFramework.Patches
|
|
|
|
|
, MVCFramework.TypesAliases
|
2016-12-30 20:41:55 +01:00
|
|
|
|
{$IFDEF SYSTEMNETENCODING}
|
|
|
|
|
, System.NetEncoding
|
2016-04-03 22:35:27 +02:00
|
|
|
|
{$ELSE}
|
2016-12-30 20:41:55 +01:00
|
|
|
|
, Soap.EncdDecd
|
2017-02-22 19:50:37 +01:00
|
|
|
|
{$ENDIF};
|
2015-04-01 17:01:23 +02:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
401 Unauthorized response should be used for missing or bad authentication, and a
|
|
|
|
|
403 Forbidden response should be used afterwards, when the user is authenticated
|
|
|
|
|
but isn<EFBFBD>t authorized to perform the requested operation on the given resource.
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const
|
2016-04-03 22:35:27 +02:00
|
|
|
|
CONTENT_HTML_FORMAT = '<html><body><h1>%s</h1><p>%s</p></body></html>';
|
2015-04-01 17:01:23 +02:00
|
|
|
|
CONTENT_401_NOT_AUTHORIZED = '401: Not authorized';
|
|
|
|
|
CONTENT_403_FORBIDDEN = '403: Forbidden';
|
|
|
|
|
|
2016-09-16 23:54:54 +02:00
|
|
|
|
function Base64DecodeString(const Value: string): string; inline;
|
2016-04-03 22:35:27 +02:00
|
|
|
|
begin
|
2016-12-30 20:41:55 +01:00
|
|
|
|
{$IFDEF SYSTEMNETENCODING}
|
2016-04-03 22:35:27 +02:00
|
|
|
|
Result := TNetEncoding.Base64.Decode(Value);
|
|
|
|
|
{$ELSE}
|
|
|
|
|
Result := DecodeString(Value);
|
|
|
|
|
{$ENDIF}
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ TMVCSalutationMiddleware }
|
2015-04-01 17:01:23 +02:00
|
|
|
|
|
|
|
|
|
constructor TMVCBasicAuthenticationMiddleware.Create(AMVCAuthenticationHandler
|
|
|
|
|
: IMVCAuthenticationHandler; Realm: string);
|
|
|
|
|
begin
|
|
|
|
|
inherited Create;
|
|
|
|
|
FMVCAuthenticationHandler := AMVCAuthenticationHandler;
|
|
|
|
|
FRealm := Realm;
|
|
|
|
|
end;
|
|
|
|
|
|
2016-02-23 22:33:21 +01:00
|
|
|
|
procedure TMVCBasicAuthenticationMiddleware.OnAfterControllerAction
|
|
|
|
|
(Context: TWebContext; const AActionName: string; const Handled: Boolean);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
begin
|
2016-04-03 22:35:27 +02:00
|
|
|
|
// do nothing
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2016-02-23 22:33:21 +01:00
|
|
|
|
procedure TMVCBasicAuthenticationMiddleware.OnBeforeControllerAction
|
|
|
|
|
(Context: TWebContext; const AControllerQualifiedClassName,
|
|
|
|
|
AActionName: string; var Handled: Boolean);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
var
|
|
|
|
|
LAuth: string;
|
|
|
|
|
LPieces: TArray<string>;
|
|
|
|
|
LRoles: TList<string>;
|
|
|
|
|
LIsValid: Boolean;
|
|
|
|
|
LIsAuthorized: Boolean;
|
|
|
|
|
LAuthRequired: Boolean;
|
2016-02-23 22:33:21 +01:00
|
|
|
|
LSessionData: TSessionData;
|
2016-09-16 23:54:54 +02:00
|
|
|
|
LPair: TPair<string, string>;
|
2015-04-01 17:01:23 +02:00
|
|
|
|
procedure SendWWWAuthenticate;
|
|
|
|
|
begin
|
|
|
|
|
Context.LoggedUser.Clear;
|
|
|
|
|
if Context.Request.ClientPreferHTML then
|
|
|
|
|
begin
|
|
|
|
|
Context.Response.ContentType := 'text/html';
|
|
|
|
|
Context.Response.RawWebResponse.Content :=
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Format(CONTENT_HTML_FORMAT, [CONTENT_401_NOT_AUTHORIZED,
|
|
|
|
|
Context.Config[TMVCConfigKey.ServerName]]);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
Context.Response.ContentType := 'text/plain';
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Context.Response.RawWebResponse.Content := CONTENT_401_NOT_AUTHORIZED + sLineBreak +
|
|
|
|
|
Context.Config[TMVCConfigKey.ServerName];
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end;
|
|
|
|
|
Context.Response.StatusCode := 401;
|
2016-02-23 22:33:21 +01:00
|
|
|
|
Context.Response.SetCustomHeader('WWW-Authenticate',
|
2016-03-03 16:32:50 +01:00
|
|
|
|
'Basic realm=' + QuotedStr(FRealm));
|
2015-04-01 17:01:23 +02:00
|
|
|
|
|
|
|
|
|
Handled := true;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure Send403Forbidden;
|
|
|
|
|
begin
|
|
|
|
|
Context.LoggedUser.Clear;
|
|
|
|
|
if Context.Request.ClientPreferHTML then
|
|
|
|
|
begin
|
|
|
|
|
Context.Response.ContentType := 'text/html';
|
|
|
|
|
Context.Response.RawWebResponse.Content :=
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Format(CONTENT_HTML_FORMAT, [CONTENT_403_FORBIDDEN,
|
|
|
|
|
Context.Config[TMVCConfigKey.ServerName]]);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
Context.Response.ContentType := 'text/plain';
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Context.Response.RawWebResponse.Content := CONTENT_403_FORBIDDEN + sLineBreak + Context.Config
|
|
|
|
|
[TMVCConfigKey.ServerName];
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end;
|
|
|
|
|
Context.Response.StatusCode := 403;
|
|
|
|
|
Handled := true;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
// check if the resource is protected
|
2016-02-23 22:33:21 +01:00
|
|
|
|
FMVCAuthenticationHandler.OnRequest(AControllerQualifiedClassName,
|
|
|
|
|
AActionName, LAuthRequired);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
if not LAuthRequired then
|
|
|
|
|
begin
|
|
|
|
|
Handled := False;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2016-04-03 22:35:27 +02:00
|
|
|
|
Context.LoggedUser.LoadFromSession(Context.Session);
|
2016-09-20 11:27:33 +02:00
|
|
|
|
LIsValid := Context.LoggedUser.IsValid;
|
|
|
|
|
if not LIsValid then
|
2015-04-01 17:01:23 +02:00
|
|
|
|
begin
|
2016-02-23 22:33:21 +01:00
|
|
|
|
// We NEED authentication
|
2015-04-01 17:01:23 +02:00
|
|
|
|
LAuth := Context.Request.Headers['Authorization'];
|
2016-04-03 22:35:27 +02:00
|
|
|
|
LAuth := Base64DecodeString(LAuth.Remove(0, 'Basic'.Length).Trim);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
LPieces := LAuth.Split([':']);
|
|
|
|
|
if LAuth.IsEmpty or (Length(LPieces) <> 2) then
|
|
|
|
|
begin
|
|
|
|
|
SendWWWAuthenticate;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// now, we have username and password.
|
|
|
|
|
// check the authorization for the requested resource
|
|
|
|
|
LRoles := TList<string>.Create;
|
|
|
|
|
try
|
2016-02-23 22:33:21 +01:00
|
|
|
|
LSessionData := TSessionData.Create;
|
|
|
|
|
try
|
|
|
|
|
FMVCAuthenticationHandler.OnAuthentication(LPieces[0], LPieces[1],
|
|
|
|
|
LRoles, LIsValid, LSessionData);
|
|
|
|
|
if LIsValid then
|
|
|
|
|
begin
|
|
|
|
|
Context.LoggedUser.Roles.AddRange(LRoles);
|
|
|
|
|
Context.LoggedUser.UserName := LPieces[0];
|
|
|
|
|
Context.LoggedUser.LoggedSince := Now;
|
|
|
|
|
Context.LoggedUser.Realm := FRealm;
|
2016-04-03 22:35:27 +02:00
|
|
|
|
Context.LoggedUser.SaveToSession(Context.Session);
|
|
|
|
|
|
2016-02-23 22:33:21 +01:00
|
|
|
|
// save sessiondata to the actual session
|
|
|
|
|
for LPair in LSessionData do
|
|
|
|
|
begin
|
2016-04-03 22:35:27 +02:00
|
|
|
|
Context.Session[LPair.Key] := LPair.Value;
|
2016-02-23 22:33:21 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
LSessionData.Free;
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
LRoles.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// authorization
|
|
|
|
|
LIsAuthorized := False;
|
|
|
|
|
if LIsValid then
|
|
|
|
|
begin
|
|
|
|
|
FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
|
|
|
|
|
AControllerQualifiedClassName, AActionName, LIsAuthorized)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if LIsAuthorized then
|
|
|
|
|
Handled := False
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if LIsValid then
|
|
|
|
|
Send403Forbidden
|
|
|
|
|
else
|
|
|
|
|
SendWWWAuthenticate;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2016-02-23 22:33:21 +01:00
|
|
|
|
procedure TMVCBasicAuthenticationMiddleware.OnBeforeRouting
|
|
|
|
|
(Context: TWebContext; var Handled: Boolean);
|
2015-04-01 17:01:23 +02:00
|
|
|
|
begin
|
2016-04-03 22:35:27 +02:00
|
|
|
|
// do nothing
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2016-09-16 23:54:54 +02:00
|
|
|
|
{ TMVCFormAuthenticationMiddleware }
|
|
|
|
|
|
|
|
|
|
constructor TMVCCustomAuthenticationMiddleware.Create(
|
|
|
|
|
AMVCAuthenticationHandler: IMVCAuthenticationHandler;
|
2016-09-18 19:19:23 +02:00
|
|
|
|
aLoginUrl: string = '/system/users/logged');
|
2016-09-16 23:54:54 +02:00
|
|
|
|
begin
|
|
|
|
|
inherited Create;
|
|
|
|
|
FMVCAuthenticationHandler := AMVCAuthenticationHandler;
|
|
|
|
|
FLoginUrl := aLoginUrl.ToLower;
|
|
|
|
|
end;
|
|
|
|
|
|
2016-09-18 19:19:23 +02:00
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.DoLogin(Context: TWebContext;
|
|
|
|
|
var Handled: Boolean);
|
|
|
|
|
var
|
|
|
|
|
lJObj: TJSONObject;
|
|
|
|
|
lUserName: string;
|
|
|
|
|
lPassword: string;
|
|
|
|
|
LRoles: TList<string>;
|
|
|
|
|
LPair: TPair<string, string>;
|
|
|
|
|
LSessionData: TSessionData;
|
|
|
|
|
LIsValid: Boolean;
|
|
|
|
|
begin
|
|
|
|
|
Context.SessionStop(False);
|
|
|
|
|
Context.LoggedUser.Clear;
|
|
|
|
|
if not Context.Request.ThereIsRequestBody then
|
|
|
|
|
begin
|
|
|
|
|
Handled := true;
|
|
|
|
|
Context.Response.StatusCode := HTTP_STATUS.BadRequest;
|
|
|
|
|
Context.Response.ContentType := TMVCMediaType.APPLICATION_JSON;
|
|
|
|
|
Context.Response.RawWebResponse.Content :=
|
|
|
|
|
'{"status":"KO", "message":"username and password are mandatory in the body request as json object"}';
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-20 19:08:01 +01:00
|
|
|
|
lJObj := TJSONObject.ParseJSONValue(Context.Request.Body) as TJSONObject;
|
2016-09-18 19:19:23 +02:00
|
|
|
|
if not Assigned(lJObj) then
|
|
|
|
|
begin
|
|
|
|
|
Handled := true;
|
|
|
|
|
SendResponse(Context, Handled, HTTP_STATUS.BadRequest);
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
lUserName := Mapper.GetStringDef(lJObj, 'username', '');
|
|
|
|
|
lPassword := Mapper.GetStringDef(lJObj, 'password', '');
|
|
|
|
|
|
|
|
|
|
if lUserName.IsEmpty or lPassword.IsEmpty then
|
|
|
|
|
begin
|
|
|
|
|
Handled := true;
|
|
|
|
|
SendResponse(Context, Handled);
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// now, we have username and password.
|
|
|
|
|
// check the authorization for the requested resource
|
|
|
|
|
|
|
|
|
|
LRoles := TList<string>.Create;
|
|
|
|
|
try
|
|
|
|
|
LSessionData := TSessionData.Create;
|
|
|
|
|
try
|
|
|
|
|
LIsValid := False;
|
|
|
|
|
FMVCAuthenticationHandler.OnAuthentication(lUserName, lPassword,
|
|
|
|
|
LRoles, LIsValid, LSessionData);
|
|
|
|
|
if not LIsValid then
|
|
|
|
|
begin
|
|
|
|
|
SendResponse(Context, Handled);
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// create the session
|
|
|
|
|
Context.LoggedUser.Roles.AddRange(LRoles);
|
|
|
|
|
Context.LoggedUser.UserName := lUserName;
|
|
|
|
|
Context.LoggedUser.LoggedSince := Now;
|
|
|
|
|
Context.LoggedUser.Realm := 'custom';
|
|
|
|
|
Context.LoggedUser.SaveToSession(Context.Session);
|
|
|
|
|
|
|
|
|
|
// save sessiondata to the actual session
|
|
|
|
|
for LPair in LSessionData do
|
|
|
|
|
begin
|
|
|
|
|
Context.Session[LPair.Key] := LPair.Value;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Context.Response.StatusCode := HTTP_STATUS.OK;
|
|
|
|
|
Context.Response.CustomHeaders.Values['X-LOGOUT-URL'] := FLoginUrl;
|
|
|
|
|
Context.Response.CustomHeaders.Values['X-LOGOUT-METHOD'] := 'DELETE';
|
|
|
|
|
Context.Response.ContentType := TMVCMediaType.APPLICATION_JSON;
|
|
|
|
|
Context.Response.RawWebResponse.Content := '{"status":"OK"}';
|
|
|
|
|
Handled := true;
|
|
|
|
|
finally
|
|
|
|
|
LSessionData.Free;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
LRoles.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.DoLogout(Context: TWebContext;
|
|
|
|
|
var Handled: Boolean);
|
|
|
|
|
begin
|
|
|
|
|
Context.SessionStop(False);
|
|
|
|
|
SendResponse(Context, Handled, HTTP_STATUS.OK);
|
|
|
|
|
end;
|
|
|
|
|
|
2016-09-16 23:54:54 +02:00
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.OnAfterControllerAction(
|
|
|
|
|
Context: TWebContext; const AActionName: string; const Handled: Boolean);
|
|
|
|
|
begin
|
|
|
|
|
// do nothing
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.SendResponse(const Context: TWebContext;
|
|
|
|
|
var Handled: Boolean; HTTPStatus: Word);
|
2016-09-18 19:19:23 +02:00
|
|
|
|
var
|
|
|
|
|
lIsPositive: Boolean;
|
|
|
|
|
lMsg: string;
|
2016-09-16 23:54:54 +02:00
|
|
|
|
begin
|
|
|
|
|
Context.LoggedUser.Clear;
|
|
|
|
|
Context.Response.CustomHeaders.Values['X-LOGIN-URL'] := FLoginUrl;
|
|
|
|
|
Context.Response.CustomHeaders.Values['X-LOGIN-METHOD'] := 'POST';
|
|
|
|
|
Context.Response.StatusCode := HTTPStatus;
|
|
|
|
|
if Context.Request.ClientPreferHTML then
|
|
|
|
|
begin
|
|
|
|
|
Context.Response.ContentType := 'text/html';
|
|
|
|
|
Context.Response.RawWebResponse.Content :=
|
2016-12-28 10:00:07 +01:00
|
|
|
|
Format(CONTENT_HTML_FORMAT, [IntToStr(HTTPStatus),
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Context.Config[TMVCConfigKey.ServerName]]);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
2016-09-18 19:19:23 +02:00
|
|
|
|
lIsPositive := (HTTPStatus div 100) = 2;
|
|
|
|
|
lMsg := ifthen(lIsPositive, 'OK', 'KO');
|
2016-09-16 23:54:54 +02:00
|
|
|
|
Context.Response.ContentType := 'application/json';
|
|
|
|
|
Context.Response.RawWebResponse.Content :=
|
2016-09-27 13:49:24 +02:00
|
|
|
|
'{"status":"' + lMsg + '", "message":"' + IntToStr(HTTPStatus) + '"}';
|
2016-09-16 23:54:54 +02:00
|
|
|
|
end;
|
|
|
|
|
Handled := true;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.OnBeforeControllerAction(
|
|
|
|
|
Context: TWebContext; const AControllerQualifiedClassName,
|
|
|
|
|
AActionName: string; var Handled: Boolean);
|
|
|
|
|
var
|
|
|
|
|
LIsValid: Boolean;
|
|
|
|
|
LIsAuthorized: Boolean;
|
|
|
|
|
LAuthRequired: Boolean;
|
|
|
|
|
begin
|
|
|
|
|
// check if the resource is protected
|
|
|
|
|
FMVCAuthenticationHandler.OnRequest(AControllerQualifiedClassName,
|
|
|
|
|
AActionName, LAuthRequired);
|
|
|
|
|
if not LAuthRequired then
|
|
|
|
|
begin
|
|
|
|
|
Handled := False;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Context.LoggedUser.LoadFromSession(Context.Session);
|
|
|
|
|
LIsValid := Context.LoggedUser.IsValid;
|
|
|
|
|
if not LIsValid then
|
|
|
|
|
begin
|
2016-12-28 10:00:07 +01:00
|
|
|
|
Context.SessionStop(False);
|
2016-09-16 23:54:54 +02:00
|
|
|
|
SendResponse(Context, Handled);
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// authorization
|
|
|
|
|
LIsAuthorized := False;
|
|
|
|
|
FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
|
|
|
|
|
AControllerQualifiedClassName, AActionName, LIsAuthorized);
|
|
|
|
|
|
|
|
|
|
if LIsAuthorized then
|
|
|
|
|
Handled := False
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if LIsValid then
|
|
|
|
|
SendResponse(Context, Handled, HTTP_STATUS.Forbidden)
|
|
|
|
|
else
|
|
|
|
|
SendResponse(Context, Handled, HTTP_STATUS.Unauthorized);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCCustomAuthenticationMiddleware.OnBeforeRouting(Context: TWebContext;
|
|
|
|
|
var Handled: Boolean);
|
|
|
|
|
begin
|
2016-09-18 19:19:23 +02:00
|
|
|
|
if (Context.Request.PathInfo.ToLower = FLoginUrl) then
|
2016-09-16 23:54:54 +02:00
|
|
|
|
begin
|
2016-09-18 19:19:23 +02:00
|
|
|
|
Handled := False;
|
|
|
|
|
if (Context.Request.HTTPMethod = httpPOST)
|
|
|
|
|
and (Context.Request.ContentType.StartsWith(TMVCMediaType.APPLICATION_JSON))
|
|
|
|
|
then
|
2016-09-16 23:54:54 +02:00
|
|
|
|
begin
|
2016-09-18 19:19:23 +02:00
|
|
|
|
DoLogin(Context, Handled);
|
2016-09-16 23:54:54 +02:00
|
|
|
|
end;
|
2016-09-18 19:19:23 +02:00
|
|
|
|
if Context.Request.HTTPMethod = httpDELETE then
|
2016-09-16 23:54:54 +02:00
|
|
|
|
begin
|
2016-09-18 19:19:23 +02:00
|
|
|
|
DoLogout(Context, Handled);
|
2016-09-16 23:54:54 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Context.LoggedUser.LoadFromSession(Context.Session);
|
|
|
|
|
if not Context.LoggedUser.IsValid then
|
|
|
|
|
begin
|
|
|
|
|
Send401Unauthorized;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// authorization
|
|
|
|
|
LIsAuthorized := False;
|
|
|
|
|
if LIsValid then
|
|
|
|
|
begin
|
|
|
|
|
FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
|
|
|
|
|
AControllerQualifiedClassName, AActionName, LIsAuthorized)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if LIsAuthorized then
|
|
|
|
|
Handled := False
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if LIsValid then
|
|
|
|
|
Send403Forbidden
|
|
|
|
|
else
|
|
|
|
|
SendWWWAuthenticate;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
end;
|
|
|
|
|
|
2015-04-01 17:01:23 +02:00
|
|
|
|
end.
|