mORMot and Open Source friends
Check-in [02bb7882b5]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:{3373} ensure inherited TSQLAuthUser class will be used to create the TSQLRestClientURI.SessionUser field instance
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 02bb7882b503217939cdf996139df4531070e5e0
User & Date: ab 2017-01-31 18:15:23
Context
2017-02-01
17:23
{3374} new SplitRight() function check-in: 59e3d1e1ed user: ab tags: trunk
2017-01-31
18:15
{3373} ensure inherited TSQLAuthUser class will be used to create the TSQLRestClientURI.SessionUser field instance check-in: 02bb7882b5 user: ab tags: trunk
2017-01-30
19:24
{3372} new TSQLRestClientURI.SessionHeartbeatSeconds property also ensuring that sicClientDriven and sicSession instances are renewed check-in: fe6aa68421 user: ab tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite3/mORMot.pas.

9323
9324
9325
9326
9327
9328
9329



9330
9331
9332
9333
9334
9335
9336
.....
14890
14891
14892
14893
14894
14895
14896
14897
14898
14899
14900
14901
14902
14903
14904
14905
14906
14907
.....
14966
14967
14968
14969
14970
14971
14972
14973
14974
14975
14976
14977
14978
14979
14980
14981
14982
14983
14984
.....
16055
16056
16057
16058
16059
16060
16061









16062
16063
16064
16065
16066
16067
16068
.....
16119
16120
16121
16122
16123
16124
16125
16126
16127
16128
16129
16130


16131
16132
16133
16134
16135
16136
16137
.....
17053
17054
17055
17056
17057
17058
17059
17060
17061
17062
17063
17064
17065
17066
17067
17068
17069
17070
17071
17072
17073
17074
17075
17076
17077









17078
17079
17080
17081
17082
17083
17084
.....
32504
32505
32506
32507
32508
32509
32510









32511
32512
32513
32514
32515
32516
32517
.....
37479
37480
37481
37482
37483
37484
37485
37486
37487
37488

37489
37490
37491
37492
37493
37494
37495
.....
50902
50903
50904
50905
50906
50907
50908
50909
50910
50911
50912
50913
50914
50915
50916
.....
51158
51159
51160
51161
51162
51163
51164
51165
51166
51167
51168
51169
51170
51171
51172
    /// add the class if it doesn't exist yet as itself or as inherited class
    // - similar to AddTable(), but any class inheriting from the supplied type
    // will be considered as sufficient
    // - return the class which has been added, or was already there as
    // inherited, so that could be used for further instance creation:
    // ! fSQLAuthUserClass := Model.AddTableInherited(TSQLAuthUser);
    function AddTableInherited(aTable: TSQLRecordClass): pointer;



    /// get the index of aTable in Tables[]
    // - returns -1 if the table is not in the model
    function GetTableIndex(aTable: TSQLRecordClass): integer; overload;
    /// get the index of any class inherithing from aTable in Tables[]
    // - returns -1 if no table is matching in the model
    function GetTableIndexInheritsFrom(aTable: TSQLRecordClass): integer;
    /// get the index of aTable in Tables[]
................................................................................
    property Ident: RawUTF8 index 50 read fIdent write fIdent stored AS_UNIQUE;
    /// the number of minutes a session is kept alive
    property SessionTimeout: integer read fSessionTimeOut write fSessionTimeOut;
    /// a textual representation of a TSQLAccessRights buffer
    property AccessRights: RawUTF8 index 1600 read fAccessRights write fAccessRights;
  end;

  /// class-reference type (metaclass) of the table containing the available
  // user access rights for authentication, defined as a group
  TSQLAuthGroupClass = class of TSQLAuthGroup;

  /// table containing the Users registered for authentication
  // - this class should be added to the TSQLModel, together with TSQLAuthGroup,
  // to allow authentication support
  // - you can inherit from it to add your custom properties to each user info:
  // TSQLModel will search for any class inheriting from TSQLAuthUser to manage
  // per-user authorization data
  // - by default, it won't be accessible remotely by anyone; to enhance security,
................................................................................
    /// some custom data, associated to the User
    // - Server application may store here custom data
    // - its content is not used by the framework but 'may' be used by your
    // application
    property Data: TSQLRawBlob read fData write fData;
  end;

  /// class-reference type (metaclass) of a table containing the Users
  // registered for authentication
  // - see also TSQLRestServer.OnAuthenticationUserRetrieve custom event
  TSQLAuthUserClass = class of TSQLAuthUser;

  /// class used to maintain in-memory sessions
  // - this is not a TSQLRecord table so won't be remotely accessible, for
  // performance and security reasons
  // - the User field is a true instance, copy of the corresponding database
  // content (for better speed)
  // - you can inherit from this class, to add custom session process
  TAuthSession = class(TSynPersistent)
................................................................................
    procedure FindServiceAll(const aServiceName: RawUTF8; aWriter: TTextWriter); overload;
    /// the number of milliseconds after which an entry expires
    // - is 0 by default, meaning no expiration
    // - you can set it to a value so that any service URI registered with
    // RegisterFromJSON() AFTER this property modification may expire
    property TimeOut: integer read fTimeOut write fTimeOut;
  end;










  /// class-reference type (metaclass) of a REST server
  TSQLRestServerClass = class of TSQLRestServer;

  /// some options for TSQLRestServer process
  // - read-only rsoNoAJAXJSON indicates that JSON data is transmitted in "not
  // expanded" format: you should NEVER change this option by including
................................................................................
  // - any published method of descendants must match TSQLRestServerCallBack
  // prototype, and is expected to be thread-safe
  TSQLRestServer = class(TSQLRest)
  protected
    fVirtualTableDirect: boolean;
    fHandleAuthentication: boolean;
    fBypassORMAuthentication: TSQLURIMethods;
    fAfterCreation: boolean;
    fOptions: TSQLRestServerOptions;
    /// the TSQLAuthUser and TSQLAuthGroup classes, as defined in model
    fSQLAuthUserClass: TSQLAuthUserClass;
    fSQLAuthGroupClass: TSQLAuthGroupClass;


    /// how in-memory sessions are handled
    fSessionClass: TAuthSessionClass;
    /// will contain the in-memory representation of some static tables
    // - this array has the same length as the associated Model.Tables[]
    // - fStaticData[] will contain pure in-memory tables, not declared as
    // SQLite3 virtual tables, therefore not available from joined SQL statements
    fStaticData: TSQLRestDynArray;
................................................................................
    // from URI() will call directly the corresponding TSQLRestStorage
    // instance, for better speed for most used RESTful operations; but complex
    // SQL requests (e.g. joined SELECT) will rely on the main SQL engine
    // - if set to false, will use the main SQLite3 engine for all statements
    // (should not to be used normaly, because it will add unnecessary overhead)
    property StaticVirtualTableDirect: boolean read fVirtualTableDirect
      write fVirtualTableDirect;
    /// the class inheriting from TSQLAuthUser, as defined in the model
    // - during authentication, this class will be used for every TSQLAuthUser
    // table access
    // - see also the OnAuthenticationUserRetrieve optional event handler
    property SQLAuthUserClass: TSQLAuthUserClass read fSQLAuthUserClass;
    /// the class inheriting from TSQLAuthGroup, as defined in the model
    // - during authentication, this class will be used for every TSQLAuthGroup
    // table access
    property SQLAuthGroupClass: TSQLAuthGroupClass read fSQLAuthGroupClass;
    /// the class inheriting from TSQLRecordTableDeleted, as defined in the model
    // - during authentication, this class will be used for storing a trace of
    // every deletion of table rows containing a TRecordVersion published field
    property SQLRecordVersionDeleteTable: TSQLRecordTableDeletedClass
      read fSQLRecordVersionDeleteTable;
    /// the class inheriting from TAuthSession to handle in-memory sessions
    // - since all sessions data remain in memory, ensure they are not taking
    // too much resource (memory or process time)
    property SessionClass: TAuthSessionClass read fSessionClass write fSessionClass;









  published { standard method-based services }
    /// REST service accessible from ModelRoot/Stat URI to gather detailed information
    // - returns the current execution statistics of this server, as a JSON object
    // - this method will require an authenticated client, for safety
    // - by default, will return the high-level information of this server
    // - will return human-readable JSON layout if ModelRoot/Stat/json is used, or
    // the corresponding XML content if ModelRoot/Stat/xml is used
................................................................................
begin
  ndx := GetTableIndexInheritsFrom(aTable);
  if ndx<0 then
    if not AddTable(aTable,@ndx) then
      raise EModelException.CreateUTF8('%.AddTableInherited(%)',[self,aTable]);
  result := Tables[ndx];
end;










constructor TSQLModel.Create(CloneFrom: TSQLModel);
var i: integer;
begin
  if CloneFrom=nil then
    raise EModelException.CreateUTF8('%.Create(CloneFrom=nil)',[self]);
  fTables := CloneFrom.fTables;
................................................................................
begin
  if aModel=nil then
    raise EORMException.CreateUTF8('%.Create(Model=nil)',[self]);
  // specific server initialization
  fStatLevels := SERVERDEFAULTMONITORLEVELS;
  fVirtualTableDirect := true; // faster direct Static call by default
  fSessions := TObjectListLocked.Create; // needed by AuthenticationRegister() below
  fModel := aModel;
  fSQLAuthUserClass := TSQLAuthUser;
  fSQLAuthGroupClass := TSQLAuthGroup;

  fSQLRecordVersionDeleteTable := TSQLRecordTableDeleted;
  for t := 0 to high(Model.Tables) do
  if fModel.Tables[t].RecordProps.RecordVersionField<>nil then begin
    fSQLRecordVersionDeleteTable := fModel.AddTableInherited(TSQLRecordTableDeleted);
    break;
  end;
  fSessionClass := TAuthSession;
................................................................................
    key: RawUTF8;
begin
  result := false;
  if Sender=nil then
    exit;
  try
    Sender.SessionClose;  // ensure Sender.SessionUser=nil
    U := TSQLAuthUser.Create;
    try
      U.LogonName := trim(aUserName);
      U.DisplayName := U.LogonName;
      if aPasswordKind<>passClear then
        U.PasswordHashHexa := aPassword else
        if aHashSalt='' then
          U.PasswordPlain := aPassword else // compute SHA256('salt'+aPassword)
................................................................................
  if aPasswordKind<>passClear then
    raise ESecurityException.CreateUTF8('%.ClientSetUser(%) expects passClear',
      [self,Sender]);
  Sender.SessionClose; // ensure Sender.SessionUser=nil
  try // inherited ClientSetUser() won't fit with Auth() method below
    ClientSetUserHttpOnly(Sender,aUserName,aPassword);
    Sender.fSessionAuthentication := self; // to enable ClientSessionSign()
    U := TSQLAuthUser.Create;
    try
      U.LogonName := trim(aUserName);
      res := ClientGetSessionKey(Sender,U,[]);
      if res<>'' then
        result := Sender.SessionCreate(self,U,res);
    finally
      U.Free;






>
>
>







 







<
<
<
<







 







<
<
<
<
<







 







>
>
>
>
>
>
>
>
>







 







<
<



>
>







 







<
<
<
<
<
<
<
<
<









>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>







 







<


>







 







|







 







|







9323
9324
9325
9326
9327
9328
9329
9330
9331
9332
9333
9334
9335
9336
9337
9338
9339
.....
14893
14894
14895
14896
14897
14898
14899




14900
14901
14902
14903
14904
14905
14906
.....
14965
14966
14967
14968
14969
14970
14971





14972
14973
14974
14975
14976
14977
14978
.....
16049
16050
16051
16052
16053
16054
16055
16056
16057
16058
16059
16060
16061
16062
16063
16064
16065
16066
16067
16068
16069
16070
16071
.....
16122
16123
16124
16125
16126
16127
16128


16129
16130
16131
16132
16133
16134
16135
16136
16137
16138
16139
16140
.....
17056
17057
17058
17059
17060
17061
17062









17063
17064
17065
17066
17067
17068
17069
17070
17071
17072
17073
17074
17075
17076
17077
17078
17079
17080
17081
17082
17083
17084
17085
17086
17087
.....
32507
32508
32509
32510
32511
32512
32513
32514
32515
32516
32517
32518
32519
32520
32521
32522
32523
32524
32525
32526
32527
32528
32529
.....
37491
37492
37493
37494
37495
37496
37497

37498
37499
37500
37501
37502
37503
37504
37505
37506
37507
.....
50914
50915
50916
50917
50918
50919
50920
50921
50922
50923
50924
50925
50926
50927
50928
.....
51170
51171
51172
51173
51174
51175
51176
51177
51178
51179
51180
51181
51182
51183
51184
    /// add the class if it doesn't exist yet as itself or as inherited class
    // - similar to AddTable(), but any class inheriting from the supplied type
    // will be considered as sufficient
    // - return the class which has been added, or was already there as
    // inherited, so that could be used for further instance creation:
    // ! fSQLAuthUserClass := Model.AddTableInherited(TSQLAuthUser);
    function AddTableInherited(aTable: TSQLRecordClass): pointer;
    /// return any class inheriting from the given table in the model
    // - if the model does not contain such table, supplied aTable is returned
    function GetTableInherited(aTable: TSQLRecordClass): TSQLRecordClass;
    /// get the index of aTable in Tables[]
    // - returns -1 if the table is not in the model
    function GetTableIndex(aTable: TSQLRecordClass): integer; overload;
    /// get the index of any class inherithing from aTable in Tables[]
    // - returns -1 if no table is matching in the model
    function GetTableIndexInheritsFrom(aTable: TSQLRecordClass): integer;
    /// get the index of aTable in Tables[]
................................................................................
    property Ident: RawUTF8 index 50 read fIdent write fIdent stored AS_UNIQUE;
    /// the number of minutes a session is kept alive
    property SessionTimeout: integer read fSessionTimeOut write fSessionTimeOut;
    /// a textual representation of a TSQLAccessRights buffer
    property AccessRights: RawUTF8 index 1600 read fAccessRights write fAccessRights;
  end;





  /// table containing the Users registered for authentication
  // - this class should be added to the TSQLModel, together with TSQLAuthGroup,
  // to allow authentication support
  // - you can inherit from it to add your custom properties to each user info:
  // TSQLModel will search for any class inheriting from TSQLAuthUser to manage
  // per-user authorization data
  // - by default, it won't be accessible remotely by anyone; to enhance security,
................................................................................
    /// some custom data, associated to the User
    // - Server application may store here custom data
    // - its content is not used by the framework but 'may' be used by your
    // application
    property Data: TSQLRawBlob read fData write fData;
  end;






  /// class used to maintain in-memory sessions
  // - this is not a TSQLRecord table so won't be remotely accessible, for
  // performance and security reasons
  // - the User field is a true instance, copy of the corresponding database
  // content (for better speed)
  // - you can inherit from this class, to add custom session process
  TAuthSession = class(TSynPersistent)
................................................................................
    procedure FindServiceAll(const aServiceName: RawUTF8; aWriter: TTextWriter); overload;
    /// the number of milliseconds after which an entry expires
    // - is 0 by default, meaning no expiration
    // - you can set it to a value so that any service URI registered with
    // RegisterFromJSON() AFTER this property modification may expire
    property TimeOut: integer read fTimeOut write fTimeOut;
  end;

  /// class-reference type (metaclass) of a table containing the Users
  // registered for authentication
  // - see also TSQLRestServer.OnAuthenticationUserRetrieve custom event
  TSQLAuthUserClass = class of TSQLAuthUser;

  /// class-reference type (metaclass) of the table containing the available
  // user access rights for authentication, defined as a group
  TSQLAuthGroupClass = class of TSQLAuthGroup;

  /// class-reference type (metaclass) of a REST server
  TSQLRestServerClass = class of TSQLRestServer;

  /// some options for TSQLRestServer process
  // - read-only rsoNoAJAXJSON indicates that JSON data is transmitted in "not
  // expanded" format: you should NEVER change this option by including
................................................................................
  // - any published method of descendants must match TSQLRestServerCallBack
  // prototype, and is expected to be thread-safe
  TSQLRestServer = class(TSQLRest)
  protected
    fVirtualTableDirect: boolean;
    fHandleAuthentication: boolean;
    fBypassORMAuthentication: TSQLURIMethods;


    /// the TSQLAuthUser and TSQLAuthGroup classes, as defined in model
    fSQLAuthUserClass: TSQLAuthUserClass;
    fSQLAuthGroupClass: TSQLAuthGroupClass;
    fAfterCreation: boolean;
    fOptions: TSQLRestServerOptions;
    /// how in-memory sessions are handled
    fSessionClass: TAuthSessionClass;
    /// will contain the in-memory representation of some static tables
    // - this array has the same length as the associated Model.Tables[]
    // - fStaticData[] will contain pure in-memory tables, not declared as
    // SQLite3 virtual tables, therefore not available from joined SQL statements
    fStaticData: TSQLRestDynArray;
................................................................................
    // from URI() will call directly the corresponding TSQLRestStorage
    // instance, for better speed for most used RESTful operations; but complex
    // SQL requests (e.g. joined SELECT) will rely on the main SQL engine
    // - if set to false, will use the main SQLite3 engine for all statements
    // (should not to be used normaly, because it will add unnecessary overhead)
    property StaticVirtualTableDirect: boolean read fVirtualTableDirect
      write fVirtualTableDirect;









    /// the class inheriting from TSQLRecordTableDeleted, as defined in the model
    // - during authentication, this class will be used for storing a trace of
    // every deletion of table rows containing a TRecordVersion published field
    property SQLRecordVersionDeleteTable: TSQLRecordTableDeletedClass
      read fSQLRecordVersionDeleteTable;
    /// the class inheriting from TAuthSession to handle in-memory sessions
    // - since all sessions data remain in memory, ensure they are not taking
    // too much resource (memory or process time)
    property SessionClass: TAuthSessionClass read fSessionClass write fSessionClass;
    /// the class inheriting from TSQLAuthUser, as defined in the model
    // - during authentication, this class will be used for every TSQLAuthUser
    // table access
    // - see also the OnAuthenticationUserRetrieve optional event handler
    property SQLAuthUserClass: TSQLAuthUserClass read fSQLAuthUserClass;
    /// the class inheriting from TSQLAuthGroup, as defined in the model
    // - during authentication, this class will be used for every TSQLAuthGroup
    // table access
    property SQLAuthGroupClass: TSQLAuthGroupClass read fSQLAuthGroupClass;
  published { standard method-based services }
    /// REST service accessible from ModelRoot/Stat URI to gather detailed information
    // - returns the current execution statistics of this server, as a JSON object
    // - this method will require an authenticated client, for safety
    // - by default, will return the high-level information of this server
    // - will return human-readable JSON layout if ModelRoot/Stat/json is used, or
    // the corresponding XML content if ModelRoot/Stat/xml is used
................................................................................
begin
  ndx := GetTableIndexInheritsFrom(aTable);
  if ndx<0 then
    if not AddTable(aTable,@ndx) then
      raise EModelException.CreateUTF8('%.AddTableInherited(%)',[self,aTable]);
  result := Tables[ndx];
end;

function TSQLModel.GetTableInherited(aTable: TSQLRecordClass): TSQLRecordClass;
var ndx: integer;
begin
  ndx := GetTableIndexInheritsFrom(aTable);
  if ndx<0 then
    result := aTable else
    result := Tables[ndx];
end;

constructor TSQLModel.Create(CloneFrom: TSQLModel);
var i: integer;
begin
  if CloneFrom=nil then
    raise EModelException.CreateUTF8('%.Create(CloneFrom=nil)',[self]);
  fTables := CloneFrom.fTables;
................................................................................
begin
  if aModel=nil then
    raise EORMException.CreateUTF8('%.Create(Model=nil)',[self]);
  // specific server initialization
  fStatLevels := SERVERDEFAULTMONITORLEVELS;
  fVirtualTableDirect := true; // faster direct Static call by default
  fSessions := TObjectListLocked.Create; // needed by AuthenticationRegister() below

  fSQLAuthUserClass := TSQLAuthUser;
  fSQLAuthGroupClass := TSQLAuthGroup;
  fModel := aModel;
  fSQLRecordVersionDeleteTable := TSQLRecordTableDeleted;
  for t := 0 to high(Model.Tables) do
  if fModel.Tables[t].RecordProps.RecordVersionField<>nil then begin
    fSQLRecordVersionDeleteTable := fModel.AddTableInherited(TSQLRecordTableDeleted);
    break;
  end;
  fSessionClass := TAuthSession;
................................................................................
    key: RawUTF8;
begin
  result := false;
  if Sender=nil then
    exit;
  try
    Sender.SessionClose;  // ensure Sender.SessionUser=nil
    U := TSQLAuthUser(Sender.Model.GetTableInherited(TSQLAuthUser).Create);
    try
      U.LogonName := trim(aUserName);
      U.DisplayName := U.LogonName;
      if aPasswordKind<>passClear then
        U.PasswordHashHexa := aPassword else
        if aHashSalt='' then
          U.PasswordPlain := aPassword else // compute SHA256('salt'+aPassword)
................................................................................
  if aPasswordKind<>passClear then
    raise ESecurityException.CreateUTF8('%.ClientSetUser(%) expects passClear',
      [self,Sender]);
  Sender.SessionClose; // ensure Sender.SessionUser=nil
  try // inherited ClientSetUser() won't fit with Auth() method below
    ClientSetUserHttpOnly(Sender,aUserName,aPassword);
    Sender.fSessionAuthentication := self; // to enable ClientSessionSign()
    U := TSQLAuthUser(Sender.Model.GetTableInherited(TSQLAuthUser).Create);
    try
      U.LogonName := trim(aUserName);
      res := ClientGetSessionKey(Sender,U,[]);
      if res<>'' then
        result := Sender.SessionCreate(self,U,res);
    finally
      U.Free;

Changes to SynopseCommit.inc.

1
'1.18.3372'
|
1
'1.18.3373'