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

Java EE Discussion :

[EJB3] [LDAP] Sécurisation des EJB3, quelque chose m'échappe. [JAAS]


Sujet :

Java EE

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut [EJB3] [LDAP] Sécurisation des EJB3, quelque chose m'échappe.
    Bonjour,

    Je rencontre de grosse difficulté à mettre en place un système d'EJB3 sécurisé via JAAS. Sachant que toute mes données utilisateur sont dans une "base" LDAP.

    Pour info: j'utilise JBOSS-4.2.1-GA sous Linux avec NetBeans 5.5 comme IDE.

    Mon application EJB est accessible via une servlet, cette dernière reçoit les requêtes HTTP et selon les paramètres et la session elle sait quoi faire.

    Tel que j'ai compris le concept j'ai implémenté ceci, pour la requête login:
    - la servlet utilise une méthode appellée login
    - à l'intèrieur, elle va appeller une méthode de classe qui va authentifier le user/pass (donné en paramètre). Cette méthode renvoit un LoginContext:
    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
     
        public static LoginContext authenticate(String username, String password)
        {
            UsernamePasswordHandler handler = 
                new UsernamePasswordHandler(username, password.toCharArray());
     
            LoginContext lc = null;
            try
            {
                lc = new LoginContext("monapp", handler);
                lc.login();        
            } 
            catch (LoginException ex)
            {
                ex.printStackTrace();
                return null;
            }        
     
            return lc;
        }
    "monapp" renvoyant à la configuration application-policy correspondante, celle ci appelle le module org.jboss.security.auth.spi.LdapExtLoginModule avec les bons paramètres qu'il faut pour LDAP...

    - si le LoginContext renvoyé est différent de null alrs je charge mon EJB :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Context context = new InitialContext();
    AppRemoteIFace app = (AppRemoteIFace)context.lookup("appli/app/remote");
    //et je met app dans la session http, mais là déjà j'imagine que c'est pas la bonne chose à faire, si?
    HttpSession session = req.getSession();
    session.setAttribute(SESSION_APP_BEAN, app);
    - à la requete suivante, je fais bêtement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    AppRemoteIFace as = (appRemoteIFace)getFromSession(req, SESSION_APP_BEAN);
    try
     {   
       app.foo();
     }
    catch (Exception e)
      {
        System.err.println("app.foo failed");
        e.printStackTrace();
      }
    Le problème:
    le login se passe bien, il utilise bien le module, l'authentification passe etc... Et si je test app.foo() dans la foulée ça fonctionne bien, (ou app.fooAdmin(), si l'utilisateur n'a pas le role admin: j'ai bel est bien une exception du au manque de droits etc...)

    MAIS: à la requête suivante, impossible de lancer app.foo() ou autre, on dirait que l'EJB perd le contexte et qu'il sait pas quoi faire.

    Le seul hack tout moche qui résout ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SecurityAssociation.setPrincipal(new SimplePrincipal((String)getFromSession(req, SESSION_USERNAME)));
    SecurityAssociation.setCredential((String)getFromSession(req, SESSION_PASSWORD));
    avant app.foo(); et là ça fonctionne.

    Mais je sais que c'est pas la bonne manière, il y a quelque chose qui m'échappe. Ai-je oublié quelque chose côté EJB? C'est plus que probable, voilà le code:
    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
     
    @Stateless
    public class App implements AppRemoteIFace, AppLocalIFace
    {
     
       @RolesAllowed({"admin"})
       public String fooAdmin()
       {
          return "fooAdmin";
       }
     
       @RolesAllowed({"user"})
       public String foo()
       {
          return "foo";
       }
    }
    Et les deux interfaces:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @Remote
    public interface AppRemoteIFace
    {
       public String fooAdmin();
       public String foo();
    }
    et:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @Local
    public interface AppLocalIFace
    {
       public String fooAdmin();
       public String foo();
    }
    Je suis perdu.
    Le gros soucis que j'ai c'est aussi de trouver de la bonne documentation à jour, je trouve des tas d'exemples complet pour ejb2 mais pas ejb3 (or il y a de sacrées différences!). Si vous en avez à me proposer qui parle d'un exemple identique (ejb3+jaas+ldap ça "devrait être" assez commun non?) je suis preneur.

    Merci de votre aide!

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Comme l'attribut l'indique, @Stateless signifie "sans état" donc pas de conservation...
    Tu devrais essayer avec @Statefull, ça devrait règler ton problème...

    A+
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Tu devrais essayer avec @Statefull, ça devrait règler ton problème...
    Même erreur, le stack trace me donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    10:34:47,794 ERROR [STDERR] javax.ejb.EJBAccessException: Authentication failure

  4. #4
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Dans le e-book sur les EJB3 (voir en post-it) il est dit au chapitre 11 Security: " Authentication must be performed before any EJB method is called. Authorization, on the other hand, occurs at the beginning of each EJB method call."

    Je pensais que l'authentification survenait une seule fois, permettant alors de récupérer les rôles (si succès) et d'instancier l'EJB. Après, à chaque appel de méthode, l'autorisation est faite selon le contexte de cette instance (si le rôle nécessaire est présent ou non).
    Il semblerait que j'ai faux donc. Dans ce cas: où l'EJB est censé trouver les informations nécessaire à l'authentification à chaque fois qu'une méthode de ce dernier est appelé?
    Est-ce dans le LoginContext? (ce qui voudrait dire qu'à l'instanciation de l'EJB ce LoginContext viens s'ajouter à l'InitialContext et que l'EJB se l'approprie, non? oui?)
    Dans ce cas, est ce que le LoginModule utilisé doit garder l'information quelque part (Principal, Credentials)?

  5. #5
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Voilà le LoginModule:
    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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
    public class AppLoginModule
        extends UsernamePasswordLoginModule
    {
     
        /**
         * Creates a new instance of AppLoginModule
         */
        public AppLoginModule()
        {
            super();
        }
     
        private transient SimpleGroup userRoles = new SimpleGroup("Roles");
     
    	public boolean validatePassword(String inputPassword, String expectedPassword)
            {		
                boolean result = false;
                UserDTO user = new UserDTO(this.getUsername(), inputPassword);
                UserDAO userDao = DAOFactory.getFactory(DAOFactory.TYPE_LDAP).getUserDAO();
     
                    System.err.println("Attempting to validate user "+getUsername()+", password: "+inputPassword);
                    result = userDao.validateUser(user);                
     
                if(result)
                {
                    PasswordCredential pc = new PasswordCredential(getUsername(),inputPassword.toCharArray());
     
                    subject.getPrivateCredentials().add(pc);
                }
     
                System.err.println("Subject : "+subject.getPrivateCredentials().toString());
     
                System.err.println("validatePassword result: "+result);
                return result;
    	}
     
     
    	public String getUsersPassword() throws LoginException {
    		return "";
    	}
     
    	public Group[] getRoleSets() throws LoginException 
            {
                System.err.println("called getRoleSets");
     
                List<RoleDTO> list = new ArrayList<RoleDTO>();
     
                RoleDAO roleDao = DAOFactory.getFactory(DAOFactory.TYPE_LDAP).getRoleDAO();
     
                    list = roleDao.getRolesForUsername(this.getUsername());		
     
                Iterator it = list.iterator();
     
                while(it.hasNext())
                {
                        RoleDTO role = (RoleDTO) it.next();
                        userRoles.addMember(new SimplePrincipal(role.getRoleName()));
                }					
     
                Group[] roleSets = {userRoles};
     
                System.err.println("list of roles: "+roleSets);
     
                return roleSets;
    	}    
     
        public boolean logout() throws LoginException
        {
            System.err.println(" * * * AppLoginModule.logout() * * *");
            return super.logout();
        }
     
    }
    Et voilà la sortie d'erreur (où on voit bien que l'on "perd" les informations de l'utilisateur:
    La requête de login:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    12:58:13,643 ERROR [STDERR] Attempting to validate user toto, password: tutu
    12:58:13,647 ERROR [STDERR] encryptSHA(user.getPassword()): 4e4Z4uLF92L3neRCnsfvBh5DSZc=
    12:58:13,668 ERROR [STDERR] Subject : [javax.resource.spi.security.PasswordCredential@3569e1]
    12:58:13,668 ERROR [STDERR] validatePassword result: true
    12:58:13,669 ERROR [STDERR] called getRoleSets
    12:58:13,689 ERROR [STDERR] getGroupsForUsername(toto) returned 1 groups
    12:58:13,708 ERROR [STDERR] getRolesForGroupName(users) returned 1 roles
    12:58:13,708 ERROR [STDERR] getRolesForUsername(toto) returned 1 roles
    12:58:13,710 ERROR [STDERR] list of roles: [Ljava.security.acl.Group;@785b38d6
    Et la requête foo:
    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
    13:12:37,602 ERROR [STDERR] Attempting to validate user null, password: null
    13:12:37,602 ERROR [STDERR] encryptSHA(user.getPassword()): null
    13:12:37,682 ERROR [STDERR] Subject : []
    13:12:37,682 ERROR [STDERR] validatePassword result: false
    13:12:37,723 ERROR [STDERR] app.foo failed for toto
    13:12:37,723 ERROR [STDERR] javax.ejb.EJBAccessException: Authentication failure
    13:12:37,723 ERROR [STDERR] 	at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.handleGeneralSecurityException(Ejb3AuthenticationInterceptor.java:68)
    13:12:37,723 ERROR [STDERR] 	at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:70)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:106)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:46)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.ejb3.stateful.StatefulContainer.dynamicInvoke(StatefulContainer.java:333)
    13:12:37,724 ERROR [STDERR] 	at org.jboss.ejb3.remoting.IsLocalInterceptor.invokeLocal(IsLocalInterceptor.java:79)
    13:12:37,725 ERROR [STDERR] 	at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:70)
    13:12:37,725 ERROR [STDERR] 	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
    13:12:37,725 ERROR [STDERR] 	at org.jboss.ejb3.stateful.StatefulRemoteProxy.invoke(StatefulRemoteProxy.java:135)
    13:12:37,725 ERROR [STDERR] 	at $Proxy68.foo(Unknown Source)
    Où sont sensés être stocké les Principals/Credentials de l'utilisateur une fois que ce dernier est loggé? (je perd le contexte mais je ne sais ni pourquoi ou alors comment le retrouver. Avec le hack, sur mon premier post ça fonctionne mais je suis pas censé faire ça)

  6. #6
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Je vous passe la config (peut-etre ai-je fait une bêtise là dedans)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <mbean code="org.jboss.naming.ExternalContext"
           name="jboss.jndi:service=ExternalContext,jndiName=external/ldap/jboss">
        <attribute name="JndiName">external/ldap/jboss</attribute>
        <attribute name="Properties">
            java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
            java.naming.provider.url=ldap://zog.net:389
            java.naming.security.principal=cn=admin,dc=jkl,dc=cellx,dc=net
            java.naming.security.authentication=simple
            java.naming.security.credentials=niark
        </attribute>
        <attribute name="InitialContext"> javax.naming.ldap.InitialLdapContext </attribute>
        <attribute name="RemoteAccess">true</attribute>
    </mbean>
    login-config.xml:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <application-policy name="app">
    		<authentication>
    			<login-module code="com.truc.muche.app.security.AppLoginModule" flag="required" />
    			<login-module code="org.jboss.security.ClientLoginModule" flag="required" >
    				<module-option name="multi-threaded">true</module-option>
    				<!--<module-option name="password-stacking">useFirstPass</module-option>-->
    				<!--<module-option name="restore-login-identity">true</module-option>-->
    			</login-module>
    		</authentication>
    	</application-policy>
    Personne n'a d'idée? J'ai vraiment besoin d'une piste là

  7. #7
    Membre chevronné
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Par défaut
    Citation Envoyé par balibalo Voir le message
    Le gros soucis que j'ai c'est aussi de trouver de la bonne documentation à jour, je trouve des tas d'exemples complet pour ejb2 mais pas ejb3 (or il y a de sacrées différences!).
    Non, je ne pense pas qu'il y ait une sacrée différence entre ejb2 et ejb3 sur le plan de la sécurité. Si tu trouves quelque chose qui fonctionne bien pour ejb2, ça devrait fonctionner de la même manière pour ejb3, car ejb3 a apporté des changements sur le modèle de programmation et de déploiement, mais pas sur l'architecture, sinon tous les modules des serveurs d'applications seraient à réécrire totalement, ce qui n'est pas le cas. Il faudrait donc essayer d'adapter les exemples que tu as pour ejb2 vers ejb3.

  8. #8
    Membre averti
    Inscrit en
    Octobre 2003
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 20
    Par défaut
    Citation Envoyé par manblaizo Voir le message
    Il faudrait donc essayer d'adapter les exemples que tu as pour ejb2 vers ejb3.
    Cet exemple est "assez" complet (même si il ne traite pas du tout de la manière à interagir avec LDAP) http://www.javaworld.com/javaworld/j...as.html?page=1
    C'est le seul que j'ai trouvé de potable.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Quelque chose m'échappe en prog. objet
    Par Luthecia dans le forum Windows Forms
    Réponses: 2
    Dernier message: 07/09/2013, 19h08
  2. [iText] width, height, quelque chose m'échappe ?
    Par garthos dans le forum Documents
    Réponses: 0
    Dernier message: 05/04/2012, 09h59
  3. DMV - quelque chose m'échappe.
    Par Philippe Robert dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 14/12/2010, 16h43
  4. [C#] Quelque chose m'échappe...
    Par diaboloche dans le forum Windows Forms
    Réponses: 4
    Dernier message: 25/03/2006, 19h41
  5. [JAAS] Accès à des EJB3 déployé sous JBoss
    Par MustaghAttack dans le forum Java EE
    Réponses: 6
    Dernier message: 22/08/2005, 13h24

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