web-dev-qa-db-fra.com

Utiliser intercept-url dans Spring security

Quelle est la méthode préférée pour créer des modèles dans l'élément intercept-url dans la sécurité Spring? Je crée un service Web (RESTful) et je demande actuellement à tous les utilisateurs d'être connectés et d'avoir le rôle ROLE_USER. Ensuite, des contraintes supplémentaires sont appliquées par les annotations @PreAuthorize sur la couche de service. Cependant, est-il courant d'ajouter également plusieurs éléments intercept-url ayant une configuration différente?

16
LuckyLuke

Je devrais penser que "la voie préférée" est [nécessairement] subjective. J'avais <intercept-url> éléments dans mon security.xml, mais je les ai abandonnés au profit d'annotations @RequestMapping avec @PreAuthorize sur les contrôleurs. C'est une préférence purement personnelle (dans mon cas), car je préfère conserver les choses en Java plutôt que dans les espaces de noms XML, dans la mesure du possible.

Vous pouvez utiliser l’un, l’autre ou les deux, et rendre l’annotation plus efficace - vous pouvez, par exemple, obtenir les éléments suivants:

security.xml :

<intercept-url pattern="/something" access="hasRole('ROLE_USER')"/>

YourController.Java :

@RequestMapping(value="/something/else")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomethingElseContents(){ return "somethingelse"; }

Comme je l'ai dit, il semble que ce soit simplement une question de préférence. L'utilisation de l'espace de noms XML présente l'avantage que les règles d'accès de base sont regroupées, faciles à lire et à suivre. Les règles imposées par @PreAuthorize (ou les autres variantes d’annotation) sont particulièrement sexy car vous pouvez y appeler votre propre expression SpEL et baser votre décision d’autorisation sur l’accès aux paramètres passés ou aux champs accessibles par la classe (par exemple @PreAuthorize("@my.project.package.hasMagicPower(#power.INVISIBILITY)")), ou une combinaison de ces options. celles-ci. Vous pouvez appliquer des autorisations logiques et dynamiques qui ne sont par ailleurs pas disponibles pour l'option d'espace de nom.

Bien sûr, vous pouvez appliquer une logique rudimentaire avec les symboles 'et', 'ou' et '!' connectives dans les expressions SpEL de l'espace de noms (et vous pourrez peut-être accéder à des méthodes de classe externe [booléen] via l'indicateur @ dans le code XML), mais tout ce qui est spécifié dans le code XML doit être statique.


tl; dr : La préférence personnelle est la préférence, mais si vous voulez ou avez besoin d'une souplesse dynamique dans la gestion de vos autorisations, vous devez utiliser des annotations. Si vous ne voulez ni n'avez besoin de flexibilité dynamique, vous avez l'option (et un argument solide suggérerait que l'option d'espace de noms est meilleure par rapport à SoC). Je préfère laisser le Java le gérer pour la flexibilité et parce qu'une fois que j'ai configuré mon XML, je veux le laisser tranquille et me concentrer sur Java. En outre, il existe un contre-argument assez convaincant à la vue SoC, à savoir qu'une application Java correctement conventionnée aura ses contrôleurs dans des packages faciles à trouver avec un contrôle évident par nom.


encore tl; dr : Meh. Six de l'un, une demi-douzaine de l'autre. Je dis po-tay-to.

18
cabbagery

La plupart des applications Web utilisant Spring Security ne comportent que quelques intercept-urls, car elles ne nécessitent que des exigences de sécurité très élémentaires. Vous devez disposer d'un accès non authentifié aux écrans de connexion et d'erreur de connexion et généralement à certains aspects du site public. Il peut donc s'agir de quelques modèles d'URL. Ensuite, il y a souvent une section admin, et tout le reste est ROLE_USER.

Si vous avez besoin de plus de rôles, il est habituel de les associer à des composants de chemin d'accès d'URL de niveau supérieur. Bien que cela ne soit pas nécessaire, il est plus facile de s’assurer que les ressources sont correctement protégées. 

<http realm="Contacts Realm" use-expressions="false">
    <intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/admin/*" access="ROLE_ADMIN"/>
    <intercept-url pattern="/secret/*" access="ROLE_SECRET"/>
    <intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN,ROLE_SECRET"/>
    <http-basic/>
</http>

En fonction de vos cas d'utilisation, vous devez décider si vous souhaitez autoriser les personnes à jouer plusieurs rôles. C’est un peu plus difficile à gérer dans l’application. Par conséquent, la plupart des personnes disposant d’une sécurité simple la configurent de sorte que les utilisateurs aient exactement un rôle, puis qu’ils autorisent plusieurs rôles à accéder à du contenu protégé. Bien entendu, l’autre façon de procéder consiste à définir un rôle par modèle d’URL et à attribuer plusieurs rôles aux utilisateurs.

Quoi qu'il en soit, la réponse à votre question (ou au moins à la question que je pense que vous posez) est que la chose habituelle à faire est un composant de chemin d'accès de niveau supérieur par rôle protégeant toutes les ressources avec les mêmes restrictions de sécurité. Bien entendu, vous regroupez également des fonctionnalités sous ce préfixe de chemin. Certaines personnes détestent donc cette structure et d'autres préfèrent simplement utiliser des annotations dans le code. J'aime ma sécurité lorsque je la vois au même endroit et que je peux facilement dire quelle est la sécurité attendue simplement en regardant l'URL. 

8
Old Pro

La configuration de SpringSecurity dépend de l'authentification sélectionnée pour votre application: Par exemple, pour l'authentification de formulaire, vous souhaitez configurer l'URL de connexion et l'URL de déconnexion sans succès:

<http realm="Contacts Realm">
    <intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/>
    <logout logout-success-url="/index.jsp"/>
</http>

Dans le cas d'une authentification de base, vous n'avez pas les URL de connexion et de déconnexion et la configuration est plus simple:

<http realm="Contacts Realm">
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <http-basic/>
</http>

Si vous sélectionnez l'authentification de base, utilisez le deuxième exemple.

3
Michael

Oui, il est assez courant de définir plusieurs modèles d'interception d'URL, puis d'ajouter des annotations pour limiter davantage les ressources.

Vous pouvez également utiliser un répertoire pour chaque restriction afin de ne pas avoir besoin d'annotations. Ex./user/** requiert ROLE_USER,/admin/** requiert ROLE_ADMIN, etc.

N'oubliez pas que lorsque vous utilisez l'une ou l'autre méthode, son impact sur la sécurité en cas d'erreur.

Si vous utilisez intercept url, vous devez placer les lignes dans le bon ordre, par exemple:

<intercept-url pattern="/**" access="permitAll"/>
<intercept-url pattern="/user/**" access="hasRole('ROLE_USER')"/>

Cela ne fonctionnera pas, car vous définissez tous les accès dans la première ligne, les lignes doivent donc être inversées. Si un débutant travaille sur votre projet et inverse les lignes, cela pourrait être un gros problème.

Si vous utilisez des annotations, vous pouvez supprimer la ligne d'annotation par erreur en laissant une faille de sécurité dans votre application.

@PreAuthorize("hasRole('ROLE_USER')")

Si vous réutilisez une classe de contrôleur entre deux projets et si vous voulez autoriser ROLE_USER à toutes les méthodes du contrôleur dans l'autre projet, alors que l'autre projet utilisant le code commun requiert ROLE_ADMIN, le moyen le plus simple d'y parvenir est d'utiliser URL d'interception. 

Alors gardez à l'esprit, @PreAuthorize sera codé en dur et partagé entre les projets. Vous pouvez étendre les classes et ajouter différents @PreAuthorize pour chaque projet, mais cela ajoute une complexité supplémentaire.

J'aime utiliser intercept-url pour sécuriser une zone entière, telle que/user/**, car il y a moins de risque de supprimer une annotation par erreur.

Si j'ai besoin d'ajouter un accès de grain fin, j'ajoute une annotation à la méthode dans le contrôleur qui est déjà sécurisée par intercept-url, mais cela se produit très rarement.

2
otterslide

L'interception d'URL peut se faire de cette façon. Supposons que vos URL de service de repos commencent par /rest/.

<http auto-config="true" use-expressions="true" access-denied-page="/accessDeniedPageURL">
    <intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')"/>
    <intercept-url pattern="/view/products" access="isFullyAuthenticated()"/>        

    <form-login login-page="/landing" default-target-url="/view/products" authentication-failure-handler-ref="authenticationFailureHandler"/>
    <logout invalidate-session="true" logout-success-url="/landing" delete-cookies="JSESSIONID"/>

    <session-management invalid-session-url="/landing" session-authentication-error-url="/landing?msg=alreadyLogin">
        <concurrency-control max-sessions="1" expired-url="/landing?msg=sessionExpiredDuplicateLogin" error-if-maximum-exceeded="false"/>
    </session-management>    
</http>
2
Jeevan Patil

Spring Security est généralement bon pour l’accès basé sur les rôles. et c'est à peu près tout. Vous pouvez créer votre propre ProcessingFilter pour effectuer des tâches supplémentaires. Cependant, je trouve que cela représente beaucoup de travail pour peu d’avantages.

L'alternative consiste à utiliser des intercepteurs de demandes. Sur plusieurs projets de services RESTful utilisant Spring MVC, j'utilise des intercepteurs de demandes pour finaliser une authentification allant au-delà de l'accès de base aux rôles. Cela fonctionne et, à mon avis, rend la chaîne d'événements beaucoup plus facile à suivre, mais si vous traitez des milliers de transactions par minute, les demandes risquent de s'enliser.

0
chrsdbll