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)
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
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.
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
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!!!
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;