IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

Problème logique pour load html static, requête Ajax avec csrf token


Sujet :

Spring Java

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Problème logique pour load html static, requête Ajax avec csrf token
    Bonjour à tous,

    Voilà plusieurs jours que j'essaye en vain différentes solutions à mon problème. J'ai ajouté à mon application le framework Spring-Security et je n'arrive pas à le rendre actif avec une page HTML static ET j'ai un problème de logique dans mon code quand à l'utilisation du CSRF via requête ajax.
    J'ai d'abord essayer avec la page de login par défaut de Spring (le pop-up) qui marche bien mais quand je fais un logout sur ma page principale, le pop-up ne réapparaît pas. Quand je logout, je ne peux plus effectuer de requête (ce qui est bon) mais quand je refresh ma page, l'user peut à nouveau faire des requêtes sans avoir du se reconnecter.

    J'ai un Front-End côté client en Html/Js qui communique via des requêtes ajax à mon Back-End.

    Mes 2 problèmes principaux :
    1. Comment load mon login.html sur la route /login
    2. Comment envoyer les infos du token à l'user pour faire les requêtes, je le fais déjà mais problème de logique pour le logout
    3. Pourquoi après le logout, l'user en rechargeant la page peut toujours effectuer les actions ?



    Architecture ressources :
    Nom : architecture.PNG
Affichages : 363
Taille : 12,1 Ko

    login.html pour la page avec un simple formulaire de login, formulaire avec username, password et fichier JS qui s'occupe de faire la requete Ajax en POST, url : login
    index.html qui est un One-Page de toute l'application.

    WebSecurity

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
     
    	@Override
    	protected void configure(HttpSecurity http) throws Exception {
    		http
    			.httpBasic()
    				.and()
    			.authorizeRequests()
    				.antMatchers("/static/**").permitAll()
    				.antMatchers("/css/**", "/img/**", "/js/**").permitAll()
    				.anyRequest().authenticated()
    				.and()
    			.formLogin()
    				.loginPage("/login").permitAll()
    				.defaultSuccessUrl("/", true)
    				.successHandler(loginSuccessHandler())
    				.and()
    //			.logout()
    //				.invalidateHttpSession(true)
    //				.logoutUrl("/logout")
    //				.permitAll()
    			.logout()
    				//.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
    				.logoutSuccessUrl("/login")
    				//.clearAuthentication(true)
    				//.deleteCookies("JSESSIONID")
    				//.invalidateHttpSession(true)
    				.logoutSuccessHandler(logoutSuccessHandler());
     
    	}
     
    	@Autowired
    	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    		auth.inMemoryAuthentication()
    				.withUser("test").password("test").roles("TEST");
    	}
     
     
    	@Bean
    	public AuthenticationSuccessHandler loginSuccessHandler() {
    		return new CustomAuthentificationSuccessHandler();
    	}
     
    	@Bean
    	public LogoutSuccessHandler logoutSuccessHandler() {
    		return new CustomLogoutSuccessHandler();
    	}

    Pour le logout, j'ai essayé plusieurs solutions, aussi avec un LougoutHandler ou je désactive la session + cookie.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
     
    	public CustomLogoutSuccessHandler() {
    		super();
    	}
     
    	// API
     
    	@Override
    	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
    			throws IOException, ServletException {
    		System.out.println("---------------- LOGOUT OK -------------------");
    		CsrfToken token = (CsrfToken) request.getAttribute("_csrf");
    		System.out.println("Ancien token -> " + token.getToken());
    		System.out.println("Ancien header -> " + token.getHeaderName());
    		HttpSession session = request.getSession(false);
    		SecurityContextHolder.clearContext();
    		session = request.getSession(false);
    		if (session != null) {
    			session.invalidate();
    		}
     
    		for (Cookie c : request.getCookies()) {
    			c.setMaxAge(0);
    		}
    		super.onLogoutSuccess(request, response, authentication);
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    @Configuration
    @EnableWebMvc
    public class MvcConfigView extends WebMvcConfigurerAdapter {
     
    	public MvcConfigView() {
    		super();
    	}
     
     
    	@Override
    	public void addViewControllers(ViewControllerRegistry registry) {
    		//forward:index.html
    		// /static/login.html
    		registry.addViewController("/login").setViewName("login.html");
    		registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    		//registry.addViewController("/logout").setViewName("login.html");
    	}
     
    /*
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    		registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    	}
    	*/
    }

    Donc problème ici d'abord, comment load avec le bon path ma page login.html ?

    Ensuite, comme j'utilise des requêtes Ajax, je dois aller chercher les infos de la session, notamment pour le token csrf pour les passer dans mes requêtes ajax, ce que je fais via un GET dès le chargement de la page index.html


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    		function getCsrfTokenAjax() {
    			$.ajax({
    				url: "getCsrfToken",
    				method: 'GET'
    			})
    			.done(function(data, textStatus, jqXHR) {
    				getCsrfToken(jqXHR);
    			});
    		}
     
    		function getCsrfToken(jqXHR) {
    		    $('meta[name="X-CSRF-TOKEN"]').attr('content', 
    		jqXHR.getResponseHeader('X-CSRF-TOKEN'));
    		    $('meta[name="X-CSRF-HEADER"]').attr('content', 
    		jqXHR.getResponseHeader('X-CSRF-HEADER'));
    		}
     
    		function setHeaderWithCsrfToken(request) {
    		    var token = $('meta[name="X-CSRF-TOKEN"]').attr('content');
    		    var header = $('meta[name="X-CSRF-HEADER"]').attr('content');
    		    var param = $('meta[name="X-CSRF-PARAM"]').attr('content');
    		    request.setRequestHeader(header, token);
    		}
    Au niveau du controller, ça renvoie les informations au client :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	@GetMapping("/getCsrfToken")
    	public void getCsrfToken(HttpServletRequest request, HttpServletResponse response) {
    		logger.info("ROUTE --> /getCsrfToken");
    		//CsrfToken token = (CsrfToken) request.getSession().getAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME);
    		CsrfToken token = (CsrfToken) request.getAttribute("_csrf");
    		// Spring Security will allow the Token to be included in this header name
    		response.setHeader("X-CSRF-HEADER", token.getHeaderName());
    		System.out.println("New Header -> " + token.getHeaderName());
    		// Spring Security will allow the token to be included in this parameter name
    		response.setHeader("X-CSRF-PARAM", token.getParameterName());
    		// this is the value of the token to be included as either a header or an HTTP parameter
    		response.setHeader("X-CSRF-TOKEN", token.getToken());	
    		System.out.println("New Token -> " + token.getToken());
    	}

    Et donc pour chaque requete j'ajoute ces informations dans le header
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    beforeSend: function (request) {
    	                setHeaderWithCsrfToken(request);
    	            }
    Mon problème ici, pourquoi après un logout + un refresh de la page l'user peut toujours effectuer des requêtes, je suppose que c'est un problème de logique avec le requête GET que je fais au début du chargement de ma page index.html..
    Je vois bien qu'après un logout, le token change mais qu'elle est l'intérêt si je peux aller GET ce nouveau token alors que l'user n'est plus censé pouvoir y accéder (dans le cas ou il modifierait le JS).

    J'espère que quelqu'un sera m'aider parce qu'après 4 jours de recherche, j'en ai perdu la patience

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 960
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 960
    Points : 4 389
    Points
    4 389
    Par défaut
    Le CSRF n'est pas un mécanisme d'authentification :
    c'est un mécanisme de protection contre l'injection de scripts qui peuvent profiter du fait que la victime soit authentifiée pour faire encore plus de dégâts,

    votre configuration HttpSecurity spécifie que l'authentification se fait en HTTP Basic mais on ne voit rien dans votre client qui construit le header HTPP avec le "Authorization Basic" …
    donc vous avez plutôt un problème de ce côté… cela "sent" le mélange de concept…
    si le refresh de la page re-authentifie effectivement l'utilisateur, peut être avez vous un javascript qui se connecte avec le http Authorization Basic header à ce moment là…

    Tracez les requêtes côté browser et mettez des points d'arrêt côté serveur…
    ou faites vos tests unitaires avec MockMvc directement sur les points d'entrée MVC : en éliminant la page de l'équation vous irez sans doute plus vite à la source du problème.

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Merci pour ton commentaire. Au final est-ce que le HttpBasic est nécessaire pour l'implémentation de connexion comme je souhaite ?

    Au départ j'avais essayé sans et le résultat ne changeait pas. A la base quand j'avais essayé avec la page de login par défaut de spring (un pop-up), la connexion marchait mais le logout n'avait aucun effet. Pourtant quand je fais un /logout je vois clairement que ma session s'invalide.

    Mais en utilisant le logout par défaut, spring ne nous bloque plus si on refresh la page, il ne propose plus le pop-up. Il rappelle donc ma méthode getCsrfToken dans le Controller et l'user peut à nouveau utiliser les routes sans authentification.

    Que devrais-je faire ? Et pourquoi Spring, par défaut après un logout ne nous force pas à nous ré-authentifier ?

  4. #4
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 960
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 960
    Points : 4 389
    Points
    4 389
    Par défaut
    Citation Envoyé par Chinabe Voir le message
    Merci pour ton commentaire. Au final est-ce que le HttpBasic est nécessaire pour l'implémentation de connexion comme je souhaite ?
    Non

    Citation Envoyé par Chinabe Voir le message
    Au départ j'avais essayé sans et le résultat ne changeait pas. A la base quand j'avais essayé avec la page de login par défaut de spring (un pop-up), la connexion marchait mais le logout n'avait aucun effet. Pourtant quand je fais un /logout je vois clairement que ma session s'invalide.

    Mais en utilisant le logout par défaut, spring ne nous bloque plus si on refresh la page, il ne propose plus le pop-up. Il rappelle donc ma méthode getCsrfToken dans le Controller et l'user peut à nouveau utiliser les routes sans authentification.
    Le problème n'a rien à voir avec le Csrf : si l'utilisateur est toujours connecté après le /logout c'est que celui-ci ne fait pas son travail complètement : clear security context, invalidate session, ...

    Citation Envoyé par Chinabe Voir le message
    Que devrais-je faire ? Et pourquoi Spring, par défaut après un logout ne nous force pas à nous ré-authentifier ?
    Parce que c'est un requirement "business" et non pas technique : où l'utilisateur est envoyé après un logout et que peut faire un "anonymous" dépend de chaque application.

Discussions similaires

  1. [Qt WebKit] Requête Ajax avec JQuery pour charger un fichier XML
    Par Maxbester dans le forum Moteurs Web
    Réponses: 0
    Dernier message: 17/12/2012, 14h42
  2. Evénement load, images et requêtes ajax
    Par eckerdecker dans le forum jQuery
    Réponses: 5
    Dernier message: 16/11/2011, 16h40
  3. [Dojo] Requête AJAX avec paramètre avec DOJO
    Par Tavarez59 dans le forum Bibliothèques & Frameworks
    Réponses: 10
    Dernier message: 19/06/2009, 14h50
  4. [JQuery] Requête ajax avec jQuery
    Par ApheX2 dans le forum jQuery
    Réponses: 3
    Dernier message: 28/08/2008, 23h40
  5. [MooTools] requête ajax avec Mootools
    Par oneTime dans le forum Bibliothèques & Frameworks
    Réponses: 1
    Dernier message: 14/04/2008, 11h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo