Sécurisation des applications JAX-RS dans le conteneur web

Vous pouvez utiliser les services de sécurité disponibles dans le conteneur web pour sécuriser les ressources REST (Representational State Transfer). Vous pouvez configurer des mécanismes de sécurité qui définissent l'authentification des utilisateurs, la sécurité du transport, le contrôle des autorisations et les mappages des utilisateurs à des rôles.

Avant de commencer

Pour définir correctement des contraintes de sécurité, vous devez être familiarisé avec l'application et les ressources REST qu'elle expose. Ainsi, vous pouvez déterminer les rôles de sécurité appropriés nécessaires à l'application et les ressources individuelles qu'elle expose.

Pour expliquer la sécurisation d'une application REST, cette rubrique utilise l'exemple d'application REST, AddressBookApp.

Vous devez installer l'application sur le serveur d'applications. Par exemple, après avoir installé l'application AddressBookApp, le descripteur de déploiement AddressBookApp qui se trouve dans le répertoire profile_root/config/cells/cellName/applications/applicationName.ear/deployments/applicationName_war/applicationName.war/WEB-INF se présente comme suit :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp_1255468655347">
 <display-name>Sample REST Web Application</display-name>
  <servlet>
    <servlet-name>AddressBookApp</servlet-name>
    <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
    <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.test.AddressBookApplication</param-value>
</init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>AddressBookApp</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>
Dans cet exemple, le mappage de servlet indique les ressources REST REST gérée sous le répertoire /app_root_context/rest, où app_root_context correspond à ce que vous configurez au cours de l'installation de l'application. Le contexte racine par défaut est /.

Vous devez activer la sécurité pour WebSphere Application Server.

Pourquoi et quand exécuter cette tâche

Vous pouvez utiliser le conteneur web pour appliquer l'authentification et des contraintes d'autorisation à l'application REST exécutée dans l'environnement du serveur d'applications. L'authentification est une condition de sécurité de base pour les ressources REST de gestion qui nécessitent un niveau minimum de sécurité et une sécurité renforcée en fonction de l'identité de l'appelant.

Vous pouvez configurer les mécanismes de sécurité suivants pour les ressources REST :
  • Authentification des utilisateurs dans l'application en utilisant l'authentification de base HTTP ou la connexion à l'aide d'un formulaire.
  • Configuration de l'application pour utiliser un canal SSL pour le transport lors de l'appel des ressources REST.
  • Définition des contraintes d'autorisation par rôle dans les modèles de ressources REST.
  • Implémentation de l'utilisation programmatique de l'objet SecurityContext annoté pour déterminer l'identité et les rôles des utilisateurs.

Procédure

  1. Vérifiez que la sécurité est activée pour le serveur d'applications.
    1. Lancez la console d'administration WebSphere Application Server.

      Démarrez le gestionnaire de déploiement et, dans votre navigateur, tapez l'adresse du serveur WebSphere Application Server, Network Deployment. Par défaut, la console se trouve surhttp://votre_hôte.votre_domaine:9060/ibm/console.

      Si la sécurité est désactivée, vous êtes invité à saisir un ID utilisateur. Connectez-vous à l'aide d'un ID utilisateur. Cependant, lorsque la sécurité est activée, vous êtes invité à saisir un ID utilisateur ainsi qu'un mot de passe. Connectez-vous avec un ID administrateur et un mot de passe prédéfinis.

    2. Cliquez sur Sécurité > Sécurité globale.

      Sélectionnez Activer la sécurité de l'application.

      Eviter les incidents Eviter les incidents: Vous devez activer la sécurité d'administration. La sécurité de l'application ne peut être activée que si la sécurité d'administration est activée. gotcha
  2. Ajoutez les contraintes de sécurité.
    Modifiez le fichier web.xml de l'application ou utilisez un outil d'assemblage pour ajouter des contraintes de sécurité à l'application. Le fragment de code suivant est une contrainte de sécurité appliquée à l'exemple d'application AddressBookApp :
    <!-- Security constraint for the sample application -->
      <security-constraint id="SecurityConstraint_1">
        <!-- This defines the REST resource associated with the constraint. -->
        <web-resource-collection id="WebResourceCollection_1">
          <web-resource-name>AddressBookApp</web-resource-name>
          <description>Protection area for Rest resource /addresses </description>
          <url-pattern>/rest/addresses</url-pattern>
          <http-method>GET</http-method>
          <http-method>POST</http-method>
        </web-resource-collection>
    
        <!—Ce code définit une contrainte d'autorisation en demandant le Role1 pour la ressource. -->
        <auth-constraint id="AuthConstraint_1">
          <description>Used to guard resources under this url-pattern </description>
          <role-name>Role1</role-name>
        </auth-constraint>
      </security-constraint>

    Dans cet exemple, il existe une ressource web dans /root_context/rest/addresses qui peut répondre à une demande HTTP GET ou POST. La contrainte de sécurité, AuthConstraint_1, est appliquée à la ressource web. La contrainte d'autorisation spécifie que le rôle Role1 est nécessaire aux utilisateurs pour pouvoir accéder à la ressource.

  3. Choisissez un ou plusieurs des mécanismes de sécurité suivants à configurer pour l'application REST.
    • Activation de l'authentification HTTP de base.
      1. Ajoutez les contraintes de sécurité en modifiant le fichier web.xml, comme indiqué précédemment.
      2. Configuration du fichier web.xml pour activer l'authentification HTTP.
        Modifiez le fichier web.xml de l'application et ajoutez l'élément suivant pour définir l'utilisation de l'authentification HTTP de base. Par défaut, l'environnement d'exécution de la sécurité du serveur d'applications utilise cette méthode d'authentification.
        <!-- Ce code définit une configuration de connexion avec l'authentification de base HTTP. -->
         <login-config>
                <auth-method>BASIC</auth-method>
                <realm-name>test realm</realm-name>
         </login-config>
        Maintenant, une méthode d'authentification de base HTTP est définie. Les utilisateurs qui tentent d'accéder à la ressource doivent se connecter en fournissant leurs données d'identification.
    • Activez la connexion par formulaire.
      1. Ajoutez les contraintes de sécurité en modifiant le fichier web.xml, comme indiqué précédemment.
      2. Modifiez le fichier web.xml de l'application et ajoutez l'élément suivant pour définir l'utilisation de la connexion par formulaire :
        <login-config>
              <auth-method>FORM</auth-method>
              <form-login-config>
                 <form-login-page>/logon.jsp</form-login-page>
                 <form-error-page>/logonError.jsp</form-error-page>
              </form-login-config>
        </login-config>
        Vous devez remplacer les valeurs de page Web logon.jsp et logonError.jsp web par la connexion par formulaire et le traitement des erreurs, respectivement. Lorsque les utilisateurs accèdent à l'application, ils sont redirigés via la page Web logon.jsp pour s'authentifier. En cas d'échec de l'authentification, les utilisateurs sont renvoyés vers la page web logonError.jsp. L'exemple suivant explique comment remplacer les pages logon.jsp et logonError.jsp dans le fichier WAR (web application archive) de l'application :
        META-INF    
              logon.jsp
              logonError.jsp
              WEB-INF/classes/
              WEB-INF/classes/
              WEB-INF/classes/com/
              WEB-INF/classes/com/test/   
              WEB- NF/classes/com/test/AddressBookApplication.class
              WEB-INF/classes/com/test/AddressBookResource.class
        Le snippet de code suivant montre un exemple de formulaire de connexion :
        <html>
        <head>
            <title>Login Page</title>
        </head>
        <h2>Hello, please log in:</h2>
        <br><br>
        <form action="j_security_check" method=post>
            <p><strong>Please Enter Your User Name: </strong>
            <input type="text" name="j_username" size="25">
            <p><p><strong>Please Enter Your Password: </strong>
            <input type="password" size="15" name="j_password">
            <p><p>
            <input type="submit" value="Submit">
            <input type="reset" value="Reset">
        </form>
        </html>
    • Activez SSL pour l'application.
      1. Ajoutez les contraintes de sécurité en modifiant le fichier web.xml, comme indiqué précédemment.
      2. Modifiez le fichier web.xml de l'application et ajoutez l'élément suivant dans l'élément de contrainte de sécurité :
        <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
         </user-data-constraint>
        Si vous ne voulez pas utiliser SSL, vous pouvez ignorer cette contrainte ou remplacer la valeur CONFIDENTIAL par NONE.
    • Activez le contrôle d'autorisation pour protéger les ressources en utilisant des modèles d'URL.
      1. Ajoutez les contraintes de sécurité en modifiant le fichier web.xml, comme indiqué précédemment.
      2. Modifiez le fichier web.xml de l'application et ajoutez l'élément suivant dans l'élément de contrainte de sécurité. Dans l'exemple suivant, Role1 et Role2 indiquent de protéger les ressources REST, à savoir /rest/addresses et /rest/resources/{i} :
        <security-constraint id="SecurityConstraint_1">
            <web-resource-collection id="WebResourceCollection_1">
              <web-resource-name>AddressBookApp</web-resource-name>
              <description>Protection area for Rest Servlet</description>
              <url-pattern>/rest/addresses</url-pattern>
              <http-method>GET</http-method>
              <http-method>POST</http-method>
            </web-resource-collection>
            <auth-constraint id="AuthConstraint_1">
                 <description> Role1 for this rest resource </description>
                 <role-name>Role1</role-name>
              </auth-constraint> 
        </security-constraint>
        
        <security-constraint id="SecurityConstraint_2">
            <web-resource-collection id="WebResourceCollection_2">
              <web-resource-name>AddressBookApp</web-resource-name>
              <description>Protection area for Rest Servlet</description>
              <url-pattern>/rest/addresses/*</url-pattern>
              <http-method>GET</http-method>
              <http-method>POST</http-method>
            </web-resource-collection>
            <auth-constraint id="AuthConstraint_2">
                 <description> Role2 for this rest resource </description>
                 <role-name>Role2</role-name>
              </auth-constraint>
        </security-constraint>

        Dans cet exemple, seuls les utilisateurs membres du rôle Role1 peuvent accéder à la ressource root-context/rest/addresses et seuls les utilisateurs membres du rôle Role2 peuvent accéder à la ressource root-context/rest/addresses/{i}.

        Eviter les incidents Eviter les incidents: Vous devez préfixer le chemin des ressources protégées avec le mappage de servlet dans les contraintes de sécurité que vous définissez. Pour empêcher le contournement des vérifications d'accès, vous pouvez mapper le servlet au chemin /*. Ce mappage protège toutes les ressources sous le contexte racine.gotcha
        Veillez à définir les rôles en insérant les éléments de définition de rôle dans l'élément <web-app>, par exemple :
        <security-role id="SecurityRole_1">
            <description>This is Role1</description>
            <role-name>Role1</role-name>
        </security-role>  
        <security-role id="SecurityRole_2">
            <description>This is Role2</description>
            <role-name>Role2</role-name>
        </security-role>  

        Les modifications que vous apportez au descripteur de déploiement sont sélectionnées automatiquement par l'environnement d'exécution du serveur d'applications et il est inutile de redémarrer l'application ou le serveur. Les autres types de modification, telles que le mappage d'URL, impliquent de redémarrer le serveur d'applications. Il est recommandé de redémarrer l'application pour appliquer les modifications.

    • Utilisation à l'aide d'un programme du contexte de sécurité annoté.
      Les développeurs d'applications peuvent utiliser l'annotation JAX-RS @SecurityContext pour appliquer en cascade à l'aide d'un programme le contexte de sécurité à la ressource sur le serveur et activer la définition des attributs de sécurité au cours de l'exécution. Le code suivant est la fonctionnalité fournie par l'interface SecurityContext :
      public String getAuthenticationScheme()
      public Principal getUserPrincipal()
      public boolean isUserInRole(String role)
      L'exemple suivant montre l'interface SecurityContext :
      package com.test;
      
      import javax.ws.rs.GET; 
      import javax.ws.rs.Consumes;
      import javax.ws.rs.POST;
      import javax.ws.rs.Path;
      import javax.ws.rs.PathParam;
      import javax.ws.rs.Produces;
      import javax.ws.rs.ext.*;
      import javax.ws.rs.core.SecurityContext;
      import javax.ws.rs.core.Context;
      
      /**   
       * Exemple de ressource qui fournit l'accès à un carnet d'adresses. 
       * 
       */
      @Path(value="/addresses")
      public class AddressBookResource {
      	
      	@Context private SecurityContext securityContext;
          
          private static String[] list = new String[] {
              "Michael",
              "Ron",
              "Jane",
              "Sam"
          };
          
          @GET
          @Produces(value="text/plain")
          public String getList() {
             // extraction du schéma d'authentification qui était utilisé (ex. : BASIC)
             String authnScheme = securityContext.getAuthenticationScheme());
             // extraction du nom du principal qui a appelé la ressource
             String username = securityContext.getUserPrincipal().getName());
             // check if the current user is in Role1 
              Boolean isUserInRole = securityContext.isUserInRole(“Role1”);
          	 
              StringBuffer buffer = new StringBuffer();
              buffer.append("{");
              for (int i = 0; i < list.length; ++i) {
                  if (i != 0) 
                      buffer.append(", ");
                  buffer.append(list[i]);
              }
              buffer.append("}");
              
              return buffer.toString();
          }
      }
    • Utilisez le gestionnaire de sécurité client pour l'authentification HTTP de base
      Vous pouvez utiliser éventuellement ce gestionnaire pour l'authentification HTTP avec une ressource JAX-RS sécurisée. L'exemple suivant monte un modèle de programmation simple pour accomplir cette tâche :
      /**
       * Ce fragment montre l'utilisation de JX-RS SecurityHandler par
       * un client pour exécuter l'authentification HTTP de base avec un service cible.
       */ 
       
       import org.apache.wink.client.ClientConfig;
       import org.apache.wink.client.Resource;
       import org.apache.wink.client.RestClient;
       import org.apache.wink.client.handlers.BasicAuthSecurityHandler;
      
       ClientConfig config = new ClientConfig();
        BasicAuthSecurityHandler secHandler = new    
       BasicAuthSecurityHandler();
      
       // Set the user credential.
       secHandler.setUsername("user1");
       secHandler.setPassword("security");
      
       // Ajout de ce gestionnaire de sécurité à la chaîne de gestionnaires.
       config.handlers(secHandler);
      
       // Création de l'instance de client REST. 
       RestClient client = new RestClient(config);
      
       // Création de l'instance de ressource pour interagir avec 
       // le substitut pour l'adresse de ressource
       resource =  
        client.resource("http://localhost:8080/path/to/resource");
      
      // Maintenant, vous pouvez appeler la ressource.
      Si vous utilisez la classe BasicAuthSecurityHandler, vérifiez que les ressources cible utilisent le schéma https pour vos adresses URL et que l'application cible est compatible avec SSL. Il est fortement conseillé d'utiliser des connexions SSL lors de l'envoi des données d'identification de l'utilisateur. Vous pouvez désactiver explicitement l'exigence relative à SSL dans la classe BasicAuthSecurityHandler en appelant la méthode setSSLRequired sur le gestionnaire de sécurité, avec la valeur false. Par défaut, cette valeur est true.
      secHandler.setSSLRequired(false);
      Vous pouvez éventuellement fournir également les données d'identification de l'utilisateur dans la ligne de commande Java™ du client, comme suit :
      java -Duser=test_user -Dpassword=your_password  your_client_program
      Vous pouvez éventuellement extraire les données d'identification depuis un fichier de propriétés dont vous définissez l'emplacement dans la ligne de commande Java, comme suit :
      java -Dclientpropsdir=directory_for_your_properties_file  your_client_program
      directory_for_your_properties_file contient le fichier wink.client.props où les propriétés user et password sont définies.

Résultats

Après avoir défini les contraintes de sécurité, l'accès aux ressources REST définies dans l'application n'est possible que si l'utilisateur est authentifié. En outre, vous avez appliqué des contraintes de rôle à des modèles d'URL de ressource pour accéder par rôle aux ressources.

Exemple

L'exemple suivant montre le descripteur de déploiement du fichier web.xml de l'exemple d'application AddressBookApp où des contraintes d'application ont été définies en suivant les étapes de la procédure précédente :
<web-app id="WebApp_1255468655347">
    <display-name>Sample REST Web Application</display-name>
    <servlet>
        <servlet-name>AddressBookApp</servlet-name>
        <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.test.AddressBookApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddressBookApp</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <security-constraint id="SecurityConstraint_1">
      <web-resource-collection id="WebResourceCollection_1">
        <web-resource-name>AddressBookApp</web-resource-name>
        <description>Protection area for Rest Servlet</description>
        <url-pattern>/rest/addresses</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint id="AuthConstraint_1">
         <description>Role1 for this rest servlet</description>
         <role-name>Role1</role-name>
      </auth-constraint> 
      <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
    </security-constraint>
    <security-constraint id="SecurityConstraint_2">
      <web-resource-collection id="WebResourceCollection_2">
        <web-resource-name>AddressBookApp</web-resource-name>
        <description>Protection area for Rest Servlet</description>
        <url-pattern>/rest/addresses/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint id="AuthConstraint_2">
         <description>Role2 for this rest servlet</description>
         <role-name>Role2</role-name>
      </auth-constraint> 
      <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
    </security-constraint>
    <security-role id="SecurityRole_1">
         <description>This is Role1</description>
         <role-name>Role1</role-name>
    </security-role>  
    <security-role id="SecurityRole_2">
         <description>This is Role2</description>
         <role-name>Role2</role-name>
    </security-role>  
    <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/logon.jsp</form-login-page>
         <form-error-page>/logonError.jsp</form-error-page>
      </form-login-config>
    </login-config>
</web-app>

Que faire ensuite

Utilisez la console d'administration pour administrer la sécurité de l'application JAX-RS.


Icône indiquant le type de rubrique Rubrique de tâche



Icône d'horodatage Dernière mise à jour: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=twbs_jaxrs_impl_securejaxrs_webcont
Nom du fichier : twbs_jaxrs_impl_securejaxrs_webcont.html