2016-02-02 1 views
0

Je développe un système client-serveur où les utilisateurs utilisent RMI (over SSL) pour l'authentification.NullPointerException rencontrée lors de l'envoi de l'objet javax.security.auth.Subject sur RMI

Le client appelle la méthode LoginInf.login():

public interface LoginIntf extends Remote {  
    Subject login(String username, char[] password) throws RemoteException;  
} 

Et sur le serveur, la méthode LoginImpl.login() est mis en œuvre:

@Override 
public Subject login(String username, char[] password) throws RemoteException { 
    logger.debug("I'm going to authenticate:"); 
    logger.debug(" username: {}", username); 
    logger.debug(" password: {}", String.valueOf(password)); 

    Subject userSubject = null; 
    try { 
     LoginContext lc = new LoginContext("AESLogin", new RemoteCallbackHandler(username, String.valueOf(password))); 
     lc.login(); 
     userSubject = lc.getSubject(); 

     // debug 
     Set<Principal> pSet = userSubject.getPrincipals();    
     pSet.stream().forEach((p) -> { 
      logger.info(p.getName()); 
     });       
    } catch (LoginException ex) { 
     logger.warn(ex); 
    } 

    return userSubject; 
} 

Toutefois, lorsque le côté client, après l'exécution de la méthode LoginIntf.login(), je reçois NullPointerException:

java.lang.NullPointerException 
    at javax.security.auth.Subject$SecureSet.readObject(Subject.java:1341) ~[?:1.8.0_66] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_66] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_66] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_66] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_66] 
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1900) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.access$300(ObjectInputStream.java:206) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream$GetFieldImpl.readFields(ObjectInputStream.java:2164) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readFields(ObjectInputStream.java:541) ~[?:1.8.0_66] 
    at javax.security.auth.Subject.readObject(Subject.java:966) ~[?:1.8.0_66] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_66] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_66] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_66] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_66] 
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1900) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[?:1.8.0_66] 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) ~[?:1.8.0_66] 
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:326) ~[?:1.8.0_66] 
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:175) ~[?:1.8.0_66] 
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:227) ~[?:1.8.0_66] 
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:179) ~[?:1.8.0_66] 
    at com.sun.proxy.$Proxy23.login(Unknown Source) ~[?:?] 
    at tw.com.asanga.aes.ife.core.IFE_MainFrame.submit_ButtonActionPerformed(IFE_MainFrame.java:537) [classes/:?] 
    at tw.com.asanga.aes.ife.core.IFE_MainFrame.access$100(IFE_MainFrame.java:32) [classes/:?] 
    at tw.com.asanga.aes.ife.core.IFE_MainFrame$2.actionPerformed(IFE_MainFrame.java:180) [classes/:?] 
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022) [?:1.8.0_66] 
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348) [?:1.8.0_66] 
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) [?:1.8.0_66] 
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) [?:1.8.0_66] 
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) [?:1.8.0_66] 
    at java.awt.Component.processMouseEvent(Component.java:6535) [?:1.8.0_66] 
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324) [?:1.8.0_66] 
    at java.awt.Component.processEvent(Component.java:6300) [?:1.8.0_66] 
    at java.awt.Container.processEvent(Container.java:2236) [?:1.8.0_66] 
    at java.awt.Component.dispatchEventImpl(Component.java:4891) [?:1.8.0_66] 
    at java.awt.Container.dispatchEventImpl(Container.java:2294) [?:1.8.0_66] 
    at java.awt.Component.dispatchEvent(Component.java:4713) [?:1.8.0_66] 
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888) [?:1.8.0_66] 
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525) [?:1.8.0_66] 
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466) [?:1.8.0_66] 
    at java.awt.Container.dispatchEventImpl(Container.java:2280) [?:1.8.0_66] 
    at java.awt.Window.dispatchEventImpl(Window.java:2750) [?:1.8.0_66] 
    at java.awt.Component.dispatchEvent(Component.java:4713) [?:1.8.0_66] 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758) [?:1.8.0_66] 
    at java.awt.EventQueue.access$500(EventQueue.java:97) [?:1.8.0_66] 
    at java.awt.EventQueue$3.run(EventQueue.java:709) [?:1.8.0_66] 
    at java.awt.EventQueue$3.run(EventQueue.java:703) [?:1.8.0_66] 
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_66] 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) [?:1.8.0_66] 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) [?:1.8.0_66] 
    at java.awt.EventQueue$4.run(EventQueue.java:731) [?:1.8.0_66] 
    at java.awt.EventQueue$4.run(EventQueue.java:729) [?:1.8.0_66] 
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_66] 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) [?:1.8.0_66] 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:728) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) [?:1.8.0_66] 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) [?:1.8.0_66] 

Je reçois la NPE même sans stocker l'objet Sujet retourné dans une variable locale et y accéder.

Je ne peux pas comprendre la cause de NPE. Je ne crois pas que ce soit la permission que je suis lié en phase DEV et ont accordé AllPermission dans mon dossier de politique:

grant { 
    permission java.security.AllPermission; 
}; 

Je sais que javax.security.auth.Subject implémente Serializable, afin d'envoyer ce RMI sur shouldn ne soit pas un problème.

Toute aide serait grandement appréciée. Merci d'avance!

+0

Je n'aime pas ce design. Le sujet doit rester sur le serveur. Vous devriez utiliser un modèle de session à distance pour cela. – EJP

+0

Merci pour la suggestion EJB. Même si j'ai résolu mon propre problème, c'est-à-dire que je peux maintenant envoyer un sujet du serveur au client, je suis impatient d'explorer vos commentaires. Pouvez-vous nous aider à expliquer pourquoi le sujet ne devrait rester que du côté serveur? Je suis nouveau à JAAS, et mon raisonnement pour envoyer le sujet au client est que plus tard, lorsque l'utilisateur doit se déconnecter, cela peut être fait en construisant un objet LoginContext avec le sujet reçu, et en appelant ensuite LoginContext.logout (). – Arthur

Répondre

1

J'ai trouvé la raison de la NPE parce que mon implémentation de l'objet Principal ne résidait que sur la base de code Server.