Outils pour utilisateurs

Outils du site


techniques:rest_api_authentication

Authentification pour les api rest

Rappel

  • stateless : la session http n'est pas maintenue entre les appels
  • statefull : la session http est maintenue entre les appels (on peut y stocker les informations de l'utilisateur)

Principe général

Dans tous les cas, le principe est qu'à chaque appel au backend :

  1. on identifie le user de l'appel
  2. on vérifie qu'il a les droits d'appeller la méthode appelée

Généralement, les api rest sont stateless, que ce soit avec ou sans protection. (Le mode statefull introduit des risques de sécurité, qu'il faut contrer en ajouter d'autres mécanismes comme le CSRF).

Mise en oeuvre possible d'authentifications pour des service rest

1.Authentication Basic

  Les solutions qui suivent sont toutes à base de token (jetons) générés et mémorisés par le backend. 
  En général, ces tokens sont uniques, et ne sont pas partagés entre les clients, chaque token représentant justement la session d'un client.
  Le client envoie ce token dans un header http (2 premiers exemples), ou dans le header http des cookies (la session est automatiquement maintenue par le navigateur)

2.Authentication Oauth compliant

  • l'utilisateur s'authentifie par une requete backend avec login et password pour obtenir un token, comme par exemple JWT
  • Il insère ensuite ce token dans le header Authorization pour toute les requêtes suivante. Authorization : Bearer <aJwtTokenOrOtherToken>
  • Le backend est donc chargé, à chaque requête (hors authent), de lire le token, de le valider,
  • Ici, le backend est généralement stateless. Si on le souhaite statefull, mais la protection doit être conservée.
  • Exemple :
    1. Mon projet jobmanager
    2. le projet orange-bank (plus complexe, définit une double authentification)
    3. le projet rte naza-emulator-back

Remarque : OAuth 2.0 est une norme complète, qui définit exactement comment les échanges doivent se passer, quelles sont les structures de données, etc … https://oauth.net/2/

3.Authentication avec Token customisé

Exemple qui définit le minimum de conf pour faire de l'authentification avec un jeton situé dans le header http : x-auth-token.
Pour cela, il utilise la classe : org.springframework.session.web.http.HeaderHttpSessionStrategy (voir javadoc) pour instancier la classe de configuration HttpSessionConfig.
Cette dernière est décorée avec @Configuration et @EnableSpringHttpSession =⇒ Utilise le concept de session http wrappé par le framework spring.

Remarque trouvée sur un forum :
Authorization is the primary header used by clients to authenticate against peers in HTTP as foreseen in RFC 7235.
Through the IANA HTTP Authentication Scheme Registry (see also: RFC 7235, sec. 5.1) you will find the Bearer scheme (defined in RFC 6750), which is closely tied to OAuth 2.0.
X-Auth-Token is pretty much providing a shortcut here as it (presumably) does not rely on either OAuth or the HTTP authentication framework.

Please note that with X-Auth-Token being an unregistered header, it is subject to no formal specification and its presence and content is always tied to a respective application. No general assumptions can be made on it.

Dans cet exemple, il y a tout le reste à mettre en place : lecture/serialisation du token, chargement de l'utilisateur pour le mettre dans

4.Authentication Authent + statefull + CSRF

  • Le user s'authentifie (avec un formulaire de login ou autre méthode). Sa session est stockée coté backend par HttpSession.
  • Ici, on est donc en statefull.
  • La session est réindiquée par le front via le cookie JESSIONID ; parfois l'échange doit se faire via l'url de ce type :
     http://<backend>/.../?...&JESSIONID=<LaSession> 
  • La session porte alors le user authentifié.
  • Pour des raisons évidentes de sécurité, une protection supplémentaire est nécessaire. On voit souvent du CSRF.
  • Exemple : mon appli qcmonline

5. Autres mécanismes

Pour être complet sur les mécanismes d'authentification envisageables : http://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml

6. Remarques

A priori, csrf n'est pas nécessaire quand on utilise un token dans Authorization, parce que le navigateur n'authentifie pas automatiquement la requête ( comme c'est le cas avec le cookie JESSIONID de java ). https://security.stackexchange.com/questions/170388/do-i-need-csrf-token-if-im-using-bearer-jwt

7.Notion de refresh_token

	Bien souvent, les tokens générés par les backend ont une date d'expiration ; OAuth 2.0 définit un mécanisme, qui est le suivant : 
	Quand le backend renvoie un token suite à un login/password successfull, il renvoie avec ce token, un refresh_token ( https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/ )
	Cela permet au frontend de renouveler son token quand il voit qu'il arrive à expiration (sans avoir besoin d'une intervention de l'utilisateur).
	L'implémentation doit suivre ceci : https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
Autre lien : 
	Authentification pour les websocket : 
		https://github.com/spring-projects/spring-framework/blob/master/src/docs/asciidoc/web/websocket.adoc#token-authentication

Spring security

Authentication

<sxh java> org.springframework.security.core.Authentication </sxh> est un objet spring qui peut représenter tantot les credentials pour la 1ere étape d'authentification, ou bien le jeton passé à chaque requete http.
Ci-dessous je ne présente que la partie où il sert de jeton.

<sxh java> UsernamePasswordAuthenticationToken </sxh> hérite de Authentication.
Cet objet est peuplé par une classe de filtre, située vers le début de la chaine de traitement de chaque requetes http ; puis cette classe appelle AuthenticationManager.authenticate(Authentication)

<sxh java> AuthenticationManager.authenticate(Authentication) </sxh> Globalement, la session HTTP porte un objet Authentication, qui permet de savoir si l'utilisateur est authentifié, et connaitre le détail de l'utilisateur.

The AuthenticationManager is just an interface, so the implementation can be anything we choose

The default implementation in Spring Security is called   'ProviderManager'   and rather than handling the authentication request itself, 
it delegates to a list of configured AuthenticationProvider s, each of which is queried in turn to see if it can perform the authentication. 
Each provider will either throw an exception or return a fully populated Authentication object.
Identification à chaque requete via header bearer 
    NazaTokenAuthenticationChainFilter.doFilterInternal() 
		--> ProviderManager.authenticate(extractedToken) 
			--> NazaTokenAuthenticationProvider(implement AuthenticationProvider).authenticate(extractedToken) 
				--> NazaTokenAuthenticationProvider.retrieveUser(extractedToken) 
					--> ... on retrouve le user ou on envoie une AuthenticationException ...
					
				Si aucune exception, alors à un moment dans ProviderManager, un code proche du suivant est appelé pour setter le user du thread exécutant la requete http : 
					SecurityContextHolder.getContext().setAuthentication(authentication);

Chaque AuthenticationProvider.authenticate(Authentication) peut lancer une exception AuthenticationException qui est la classe abstraite de BadCredentialsException, AccountExpiredException, en gros toute exception qui invalide l'autorisation).

Droits d'accès

<sxh java>

	@Secured("ROLE_USER1")
	@RequestMapping(value = "/test-with-role-user1-secured", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public void testWithRole1Secured() { ... }
	@Secured("ROLE_USER2")
	@RequestMapping(value = "/test-with-role-user2-secured", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public void testWithRole2Secured() { ... }
	@PreAuthorize("hasRole('USER1')")
	public void testWithRole1PreAuthorize() { ... }	  

</sxh>

techniques/rest_api_authentication.txt · Dernière modification: 2020/02/29 19:00 (modification externe)