#1 2015-07-27 10:51:57

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Implementing your own password hash

Hi Ab,

I need to authenticate against an existing user database which calculates a proprietary hash. The easiest way I found to do that was to declare my own TSQLAuthUser. If we make TSQLAuthUser.SetPasswordPlain virtual, I can override the hash calculation and everything works.

Will you apply this to the code base?
    procedure SetPasswordPlain(const Value: RawUTF8); virtual;

I think this part of the library needs some work though, it's very tightly bound. Perhaps if one can abstract it out to use interfaces instead, that would make extending it really easy.

PS Article forthcoming.

Offline

#2 2015-07-27 11:27:16

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Implementing your own password hash

You could sub-class the TSQLAuthUser type, and provide it in the TSQLRest model.
See http://synopse.info/forum/viewtopic.php?id=2053

Or just use the mORMot authentication just for communication, with fixed passwords and users at low level, letting your existing database with its user/password proprietary process be used for high-level authentication.
That is, do not use mORMot authentication for your business authentication.

Offline

#3 2015-07-27 11:40:00

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

Hi Ab,

Yes, that's what I do:

type
  TDummySQLUser = class(TSQLAuthUser)
  protected
    procedure SetPasswordPlain(const Value: RawUTF8); override;
  public
    constructor Create( aUserName, aPassword : RawUTF8 ); reintroduce;
  end;
  TDummySQLGroup = class(TSQLAuthGroup)
  public
    constructor Create; reintroduce;
  end;

{ TDummySQLUser }

procedure TDummySQLUser.SetPasswordPlain(const Value: RawUTF8);
begin
  PasswordHashHexa := EncryptIBPass( Value );
end;

constructor TDummySQLUser.Create( aUserName, aPassword : RawUTF8 );
begin
  inherited Create;
  fID := 1;
  LogonName := aUserName;
  PasswordHashHexa := aPassword;
  GroupRights := TDummySQLGroup.Create();
end;

{ TDummySQLGroup }

constructor TDummySQLGroup.Create;
begin
  fID := 1;
  Ident := 'User';
end;

and then in my server class:

function TAbstractServer.RetrieveRevelightUser(
  Sender: TSQLRestServerAuthentication; Ctxt: TSQLRestServerURIContext;
  aUserID: TID; const aUserName: RawUTF8): TSQLAuthUser;
var
  Res : ISQLDBRows;
begin
  Result := nil;
  Res := fDbConnection.Execute(
    'select USER_ID, USER_PASSWORD '+
      'from USERS '+
     'where ACTIVE_FLAG=? and '+
           'USER_ID=UPPER(?)',
    [
      cACTIVEFLAG_ACTIVE,
      aUserName
    ]);
  if Res.Step then begin
    Result := TDummySQLUser.Create(Res['USER_ID'], Res['USER_PASSWORD']);
  end;
end;

Which works pretty well, as long as SetPasswordPlain is virtual.

I am experiencing some other issues too. From my test client it looks like my session is disappearing. From the logs I can see the Authentication attempt come through and succeed, but then the next call to [server]/[service]._contract_ I get a

{  "errorCode":403,  "errorText":"Forbidden"  }

response.

Offline

#4 2015-07-27 11:58:25

esmondb
Member
From: London
Registered: 2010-07-20
Posts: 299

Re: Implementing your own password hash

I got the 403 error in a similar situation the other day. I had forgotten to set TSQLAuthGroup.SessionTimeout which reverted to 0.

Offline

#5 2015-07-27 12:12:19

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

That was a good idea, but setting TSQLAuthGroup.SessionTimeout to 999999 has the same effect hmm

Offline

#6 2015-07-27 12:34:08

esmondb
Member
From: London
Registered: 2010-07-20
Posts: 299

Re: Implementing your own password hash

Maybe there is something wrong with TSQLAuthGroup.SQLAccessRights. Perhaps try setting it to:

const
  SERVICE_ACCESS_RIGHTS: TSQLAccessRights =
    (AllowRemoteExecute: [reService];
    GET: []; POST: [];
    PUT: []; DELETE: []);

Offline

#7 2015-07-27 13:02:08

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

Thanks esmondb, but I'm starting to think that Ab was right and I should abandon the Auth stuff in mORMot. The issue seems to be that when CreateMissingTables is called, it creates the dummy tables, with no/basic/default information in.
This has the side effect that Group information will always be Admin (when forced to ID:1) and all the group information will always be default.

This doesn't play well with trying to force the Authentication credentials, as it keeps overriding group information from the in memory created group.

When I have more time to play, I'll see if it is possible to derive a new HTTP server that allows for a more flexible authentication/authorization model.

Offline

#8 2015-07-27 13:59:56

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

Yay! Found the problem!

The issue is in TSQLRestServerAuthenticationHttpBasic.RetrieveSession

Ab, can you please change line mORMot.pas[44879]:

    with TSQLAuthUser.Create do

to:

    with Ctxt.Server.SQLAuthUserClass.Create do

Offline

#9 2015-07-28 14:52:41

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

*bump*

Would it help if I submit a pull request?

Offline

#10 2015-07-28 15:27:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Implementing your own password hash

Please try http://synopse.info/fossil/info/9363cb2e4d

I also defined the class function ComputeHashedPassword as virtual so that you may use your own hashing algorithm for this TSQLAuthUser class.

Offline

#11 2015-07-29 06:36:28

willo
Member
From: Cape Town, South Africa
Registered: 2014-11-15
Posts: 67
Website

Re: Implementing your own password hash

Thanks Ab!

Offline

Board footer

Powered by FluxBB