Could you help with documentation for the TRO Http Api Simple Authentication Manager, specifically the On Can Write Method Security event

Hi,

I am exploring adding a REST API to my existing Delphi custom server.

As per the title, can you tell me what the OnCanWriteMethodSecurity event does and what CanWrite means?

Anything else I should know about TROHttpApiSimpleAuthenticationManager ?

Thanks

(PS the extra spaces in the title are because your forum software refused to accept it was a readable sentence without them - this needs looking into as it could adversely affect future searches. I can’t even add them as tags)

Hi,

this event allows to specify service methods that can be launched w/o session protection via setting CanWrite to False. it works similar to RequiresSession property of service

for example, if all your methods require server’s session except LoginService.Login, it can be implemented as

procedure TServerForm.ROHttpApiSimpleAuthenticationManager1CanWriteMethodSecurity(
  aServiceName, aMethodName: string; var CanWrite: Boolean);
begin
  CanWrite := not((aServiceName = 'LoginService') and (aMethodName = 'Login'));
end;

Note: this event is used only if SecurityMode is set to smPerMethod

2 Likes

Great thanks Evgeny !

I am using Delphi, ROSDK version 9.7.0.1433, Sample Project “HttpApiAuthentication”
This doesn’t see to work as you said.

In code, we have:

procedure TServerForm.ROHttpApiSimpleAuthenticationManager1CanWriteMethodSecurity(
aServiceName, aMethodName: string; var CanWrite: Boolean);
begin
CanWrite := not((aServiceName = ‘LoginService’) and (aMethodName = ‘Login’));
end;

SecurityMode is perMethod, and NewService.RequiresSession := False

Then, ALL service methods can be called without problem - Is that supposed to be like that? I thought that only LoginService.Login can be invoked if CanWrite := True for all other service methods.

Any heads up?

Hi,

You are right - protected methods should be put into different service that should have RequiresSession := True, but HttpApi Authentication feature can also forbid access to usual methods as it was shown in this sample.

try to call any “protected” method without login like

curl -verbose -X POST "http://localhost:8099/api/test/Sum" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"A\": 1,  \"B\": 2}"

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8099 (#0)
> POST /api/test/Sum HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.56.0
> Referer: rbose
> accept: application/json
> content-type: application/json
> Content-Length: 19
>
* upload completely sent off: 19 out of 19 bytes
< HTTP/1.1 401 OK
< Connection: close
< Content-Type: text/html; charset=ISO-8859-1
< Content-Length: 0
< Date: Mon, 03 Jun 2019 09:14:05 GMT
< Accept-Encoding: gzip, identity
<
* Closing connection 0

I am still confused

I tried with a different setting

CanWrite = False for ALL methods, NewSrrvice.RequireSession = True

None of the methods of NewService can be called - meaning they are still protected uniformly by NewService.RequireSession = True. In this case, what “CanWrite = False” do to them? Shouldn’t “CanWrite=False” relieve them from requiring a session, even though NewService.RequireSession = True?

TROHttpApiSimpleAuthenticationManager has two modes:

  • smWholeServer - all methods require autentication
  • smPerMethod - you can specify exception for specific method(s) via OnCanWriteMethodSecurity event.

in this sample, we allow unsecured mode only for LoginService.Login via this event:

procedure TServerForm.ROHttpApiSimpleAuthenticationManager1CanWriteMethodSecurity(
  aServiceName, aMethodName: string; var CanWrite: Boolean);
begin
  CanWrite := not((aServiceName = 'LoginService') and (aMethodName = 'Login'));
end;

Note: HTTP API logic cannot override default authentication logic of Remoting SDK but it can specify some additional restrictions over default authentication logic like LoginService.Logout method that is put in unprotected (RequiresSession = False) service, but according to HTTP API, it requires authentication token.

I understand what you said but I don’t see CanWrite work as you described

It seems totally having NO effect.

for example if CanWrite = True for LoginService, I can still call LoginService. Or you tell me, if CanWrite =True for LoginIn in the sample, when I call Login, should I expect a pass or a fail!!!

Thanks, logged as bugs://82715

bugs://82715 got closed with status fixed.

  • update TROHttpApiDispatcher.InvokeServiceMethod (uROHttpApiBaseAuthenticationManager.pas) as:
    old:
        if Assigned(fAuthenticationManager) then
          lsession :=  fAuthenticationManager.ReadAuthenticationInfo(aRequest)

new:

        if Assigned(fAuthenticationManager) then begin
          lsession :=  fAuthenticationManager.ReadAuthenticationInfo(aRequest);
          if lsession.ClientToken = '' then begin
            if fAuthenticationManager.IsNeedSession(lRoute.ServiceName,lRoute.MethodName_) then begin
              WriteErrorResponse(aResponse, aResponseData, HTTP_401_code, '');
              Exit;
            end;
          end;
        end
  • add a new method into uROHttpApiBaseAuthenticationManager.pas:
function TROHttpApiBaseAuthenticationManager.IsNeedSession(aServiceName,
  aMethodName: string): Boolean;
begin
  Result := SecurityMode = smWholeServer;
  if not Result then begin
    Result := not Assigned(OnCanWriteMethodSecurity);
    if not Result then OnCanWriteMethodSecurity(aServiceName, aMethodName, Result);
  end;
end;
1 Like