Webservice - Authorization avec un contenu Bearer + token (token non Simplicité)

Request description

Bonjour,
Dans le cadre de la mise œuvre d’un webservice “habilitation public” permettant la création d’un user, nous avons dans l’entête une entrée Authorization avec un contenu Bearer +token (le token est non Simplicité). Nativement, le socle essaie de valider le token via JWT. Comment peut-on bypasser cette vérification ? la validation du token se faisant par un système spécifique au client.

Utilisation de la class : RESTServiceExternalObject

Technical information

Instance /health
[Platform]
Status=OK
Version=5.3.31
BuiltOn=2024-03-15 13:56
Git=5.3/0ccf142afa4e52dbd9ac3d0e72cb527a5ca11e22
Encoding=UTF-8
EndpointIP=10.105.64.27
EndpointURL=http://alpha:8080/simplicite
TimeZone=Europe/Paris
SystemDate=2024-03-29 09:53:54

[Application]
ApplicationVersion=0.2
ContextPath=/simplicite
ContextURL=https://alpha.fr/simplicite
ActiveSessions=2
TotalUsers=16
EnabledUsers=14
LastLoginDate=2024-03-29 09:52:05

[Server]
ServerInfo=Apache Tomcat/9.0.62.redhat-00017
ServerType=WEB
ServerActiveSessions=0
ServerSessionTimeout=30
CronStarted=true

[OS]
Name=Linux
Architecture=amd64
Version=4.18.0-513.18.1.el8_9.x86_64
SystemEncoding=UTF-8

[Disk]
DiskFree=2977
DiskUsable=2977
DiskTotal=3062

[JavaVM]
Version=17.0.9
Vendor=Red Hat, Inc.
VMName=OpenJDK 64-Bit Server VM
VMVersion=17.0.9+9-LTS
ScriptEngine=rhino
ScriptEngineVersion=Rhino 1.7.13 2020 09 02
HeapFree=801977
HeapSize=1048576
HeapMaxSize=2097152
TotalFreeSize=1850553

[Cache]
ObjectCache=419
ObjectCacheMax=10000
ObjectCacheRatio=4
ProcessCache=419
ProcessCacheMax=10000
ProcessCacheRatio=4
APIGrantCache=1
APIGrantCacheMax=1000
APIGrantRatio=0

[Database]
Vendor=3
VendorName=postgresql
ProductName=PostgreSQL
ProductVersion=14.10
DriverName=PostgreSQL JDBC Driver
DriverVersion=42.7.1
DBDate=2024-03-29 09:53:54
DBDateOffset=0
DBPatchLevel=5;P03;504b3d3f35216ae713e5bf5df2855321
UsingBLOBs=true

[Healthcheck]
Date=2024-03-29 09:53:54
ElapsedTime=7
Simplicité logs
2024-03-29 09:54:24,556|SIMPLICITE|ERROR||http://alpha:8080/simplicite|/simplicite|ERROR|system|com.simplicite.webapp.servlets.api.ExternalObjectServlet|service||Event: Authentication error: Invalid token
2024-03-29 09:54:24,555|SIMPLICITE|ERROR||http://alpha:8080/simplicite|/simplicite|ECORED0001|system|com.simplicite.webapp.tools.ServletTool|validateJWTToken||Error Unable to process JWT token: The token was expected to have 3 parts, but got 0.

Bonjour,

Ce controle du token est conditionné par le USERTOKENS_MODE.
As tu essayé le USERTOKENS_MODE = simple au lieu de jwt ?

https://docs.simplicite.io/lesson/docs/core/system-parameters-list#usertokens_mode

Il essaie tjrs de traiter le token alors que nous souhaiterions un bypass;

2024-03-29 10:44:33,447|SIMPLICITE|ERROR||http://alpha:8080/simplicite|/simplicite|ERROR|system|com.simplicite.webapp.servlets.api.ExternalObjectServlet|service||Event: Authentication error: Invalid token

2024-03-29 10:44:33,447|SIMPLICITE|ERROR||http://alpha:8080/simplicite|/simplicite|ECORED0001|system|com.simplicite.webapp.tools.ServletTool|createAPIGrantFromToken||Error No login associated to the token

Il faut exposer cette API en public et traiter son authent custom manuellement.

En tapant sur /api ça passe nécessairement par une ident/authent Simplicité, i.e. essayer de retrouver un user déclaré dans Simplicité via un provider dûment déclaré.

Bref pour moi c’est un pb de conception, pas d’ident/authent

Exact, pourquoi vouloir une authent ? le token est sensé à un moment retrouver un login, des droits…

Sinon on a ajouté récemment un hook getAuthTokenInfo pour faire un parsing maison (ou rien du coup), ça répond peut être au besoin.

UPDATE : la doc

https://docs.simplicite.io/lesson/docs/authentication/oauth2#custom-token-validation

Bonjour,

Merci, Cela nous a permis d’avancer sur le sujet.
Néanmoins, il nous reste un point qui nous pose problème, en faisant N appels Postman

  • Le 1er appel est bien géré par la méthode getAuthTokenInfo ce qui semble indiquer que le paramétrage est fonctionnel,
  • Un 2eme appel, on reçoit un message d’erreur de jeton :
ExternalObjectServlet|service||Evénement: Authentication error: Jeton expiré
ServletTool|getAPIGrant||Erreur The cached token is expired since 1970-01-01 01:00:10

Un 3eme appel est bien géré par la méthode getAuthTokenInfo
Un 4eme, on reçoit un message d’erreur de jeton
et ainsi de suite

curl --location --request POST 'https://[URL]/api/ext/ServiceActivite’
–header ‘Accept: application/json’
–header ‘Accept-Encoding: UTF-8’
–header ‘Authorization: Bearer [token]’

Pour information, voici le retour que l’on renvoie via la méthode getAuthTokenInfo

{“valid”:true,“expiry”:10,“login”:“test2024”}

“test2024” étant un utilisateur webservice paramétré dans l’application

Cordialement,

Je ne comprends pas la logique de cette ident/authent…

Sur /api il y a 2 cas d’usage:

  1. si aucun token n’est passé, ni via le header Authorization ni via le header X-Simplicite-Authorization, c’est alors le user public qui est implicitement utilisé (et il est toujours possible d’implémenter une pseudo-logique d’authentification de l’appel via une info authentifiante passée d’une autre manière)

  2. si un token est passé via un des headers ci-dessus, il doit obligatoirement servir à identifier un user existant via un provider d’identité dument déclaré dans AUTH_PROVIDERS => la configuration de celui-ci étant utilisée pour obtenir des infos sur le token notamment sa date d’expiration. Si on parle d’un token arbitraire (i.e. non JWT = “dummy token”) ou issu d’un provider ne proposant pas de endpoint normalisé OpenIDConnect token info il faut alors implémenter le calcul des infos - notamment sa date d’expiration - de ce token dans le hook getAuthTokenInfo.

Ce qui a été paramétré :

AUTH_PROVIDERS
{
		"name":"ActiviteProvider", "type":"oauth2", "visible":false,
		"tokeninfo_mappings" : {
			"login": "login", 
			"expiry": "expiry",
			"valid": "valid"
		}
}

USERTOKENS_MODE
{
       simple
}

Nous avons essayer de modifier notre retour de méthode getAuthTokenInfo {“valid”:true,“expiry”:10,“login”:“test2024”}, en modifiant le expiry (non pas en temps seconde) mais avec une date d’expiration : cela nous donne toujours le même résultat

Avec des appels identiques via Postman, une fois on passe dans la méthode getAuthTokenInfo, une autre fois on est rejeté avant même d’y passer

Pour deux appels identiques et consécutifs sur Postman, nous avons deux retours différents. On a surement du rater un paramètre mais lequel ?

A quoi sert de configurer un bloc token info mapping s’il n’y a pas de endpoint token info associé à ce provider ?

On a utilisé la doc citée ci dessous :

https://docs.simplicite.io/lesson/docs/authentication/oauth2#custom-token-validation

En effet, nous avons une validation du token spécifique, on vérifie bien la validé du token avant de renvoyer le triplet.

Comment vérifiez vous cette validité ?

Je pose la question pour savoir si cela ne permet pas de déterminer sa durée de validité (comme c’est le cas avec un endpoint OpenIDConnect “token info” ou un simple parsing JWT).

On peut récupérer la durée de validé.

Aujourd’hui pour des tests, on met 10s pour tester en mode bouchon et nous constatons un comportement alternatif. (une fois, cela fonctionne, une fois cela ne fonctionne pas).

De notre compréhension, notre Token validé est associé à une session pendant 10 s. Hors pendant ces 10 s, si on lance plusieurs appels, alors une fois le Token va être considéré expiré par le socle Simplicité et une autre fois, il va être traité par le getAuthTokenInfo alors qu’on ne devrait plus passer dans la méthode getAuthTokenInfo tant que la session associée au Token n’est pas expirée.

Afin d’éviter toute erreur, que devons-nous renvoyer dans le expiry, un temps de validité en ms ou une date de fin de validité (expiration) ?

Il y a un mécanisme de “cache” des tokens, donc une fois expiré un token n’est plus sensé être réutilisé et certainement pas “reactivé” en lui redonnant une durée de validité = je n’ai aucune idée de la manière dont ça va se comporter si on le fait…

Bref, récupérer la vraie durée de validité du token et donnez lui cette validité (après avoir fait un clear cache complet pour être sûr de ne pas avoir ce token en “zombie” expiré dans le cache)

Ce que je ne comprend toujours pas c’est : comment validez-vous CONCRETEMENT ce token ?

Je voudrais voir si vous n’êtes pas juste en train de réinventer la roue vs des mécanismes standards qui existent déjà et fonctionnent parfaitement

On valide le token via une url (login, mdp, token) et on reçoit si le token est actif avec son temps de validé en ms.

Ca ressemble furieusement à une endpoint “token info” standard ça !

A quoi ressemble excatement la requête et la réponse ?

Requête :

[URL]?client_id=[CLient_ID]&client_secret=[Client_SECRET]&token=[TOKEN]

Réponse en enlevant les données sensibles :

{“active”:true,“exp”:1710180545}

Ca ressemble de plus en plus à un endpoint token info OpenIDConnect

Il faut donc juste parametrer l’URL de ce endpoint sur ton provider + les mappings et pas besoin d’implementer quoi que ce soit de specifique

Cf. Generic OpenIDConnect provider settings

Le paramétrage est réalisé et fonctionnel, néanmoins nous avons implémenté la méthode getAuthTokenInfo. La prise en compte de l’expiration a réglé le problème.

Merci pour le support.

Je ne valide pas cette approche puisqu’il s’agit clairement d’un provider OpenIDConnect avec un endpoint “token info” tout à fait standard.

Il suffit donc de paramétrer l’URL de ce endpoint avec le mapping ad hoc si besoin

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.