Commit 45db3678 by Michael Brachmann

revoke fixes

parent 214bb264
...@@ -19,6 +19,7 @@ type ...@@ -19,6 +19,7 @@ type
procedure AfterConstruction; override; procedure AfterConstruction; override;
procedure BeforeDestruction; override; procedure BeforeDestruction; override;
procedure RequireAdmin; procedure RequireAdmin;
procedure RequireActiveDevice;
function OpenLemsConnection: TUniConnection; function OpenLemsConnection: TUniConnection;
public public
function GetBadgeCounts: TJSONObject; function GetBadgeCounts: TJSONObject;
...@@ -50,6 +51,7 @@ begin ...@@ -50,6 +51,7 @@ begin
inherited; inherited;
ApiDB := TApiDatabaseModule.Create(nil); ApiDB := TApiDatabaseModule.Create(nil);
Logger.Log(3, 'ApiDatabaseModule created'); Logger.Log(3, 'ApiDatabaseModule created');
RequireActiveDevice;
end; end;
procedure TApiService.BeforeDestruction; procedure TApiService.BeforeDestruction;
...@@ -1228,6 +1230,70 @@ begin ...@@ -1228,6 +1230,70 @@ begin
raise EXDataHttpException.Create(403, 'Admin access required'); raise EXDataHttpException.Create(403, 'Admin access required');
end; end;
procedure TApiService.RequireActiveDevice;
var
ctx: THttpServerContext;
authHeader, b64p, payload, credId, deviceStatus: string;
parts: TArray<string>;
padLen: Integer;
payloadObj: TJSONObject;
conn: TUniConnection;
q: TUniQuery;
begin
credId := '';
try
ctx := THttpServerContext.Current;
if ctx = nil then Exit;
authHeader := ctx.Request.Headers.Get('Authorization');
if not authHeader.StartsWith('Bearer ') then Exit;
parts := authHeader.Substring(7).Split(['.']);
if Length(parts) >= 2 then
begin
b64p := parts[1].Replace('-', '+').Replace('_', '/');
padLen := (4 - Length(b64p) mod 4) mod 4;
b64p := b64p + StringOfChar('=', padLen);
payload := TEncoding.UTF8.GetString(TNetEncoding.Base64.DecodeStringToBytes(b64p));
payloadObj := TJSONObject.ParseJSONValue(payload) as TJSONObject;
if Assigned(payloadObj) then
try
credId := payloadObj.GetValue<string>('credential_id', '');
finally
payloadObj.Free;
end;
end;
except
Exit; // Malformed JWT — let Sparkle middleware reject it
end;
if credId = '' then Exit; // JWT predates this feature — allow through
deviceStatus := '';
conn := OpenLemsConnection;
try
q := TUniQuery.Create(nil);
try
q.Connection := conn;
q.SQL.Text :=
'SELECT status FROM lems.device_registrations WHERE credential_id = :CID';
q.ParamByName('CID').AsString := credId;
q.Open;
if not q.IsEmpty then
deviceStatus := q.FieldByName('status').AsString;
q.Close;
finally
q.Free;
end;
finally
conn.Free;
end;
if deviceStatus = 'revoked' then
begin
Logger.Log(2, 'RequireActiveDevice - rejected revoked credential: ' + Copy(credId, 1, 20));
raise EXDataHttpException.Create(401, 'Device access has been revoked.');
end;
end;
function TApiService.OpenLemsConnection: TUniConnection; function TApiService.OpenLemsConnection: TUniConnection;
begin begin
Result := TUniConnection.Create(nil); Result := TUniConnection.Create(nil);
......
...@@ -630,6 +630,7 @@ begin ...@@ -630,6 +630,7 @@ begin
JWT.Claims.SetClaimOfType<string>('user_id', userId); JWT.Claims.SetClaimOfType<string>('user_id', userId);
JWT.Claims.SetClaimOfType<string>('user_personnelid', userPersonnelId); JWT.Claims.SetClaimOfType<string>('user_personnelid', userPersonnelId);
JWT.Claims.SetClaimOfType<Boolean>('user_admin', userIsAdmin); JWT.Claims.SetClaimOfType<Boolean>('user_admin', userIsAdmin);
JWT.Claims.SetClaimOfType<string>('credential_id', Trim(credentialId));
Result := TJOSE.SHA256CompactToken(ServerConfig.jwtTokenSecret, JWT); Result := TJOSE.SHA256CompactToken(ServerConfig.jwtTokenSecret, JWT);
finally finally
JWT.Free; JWT.Free;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment