Я разрабатываю систему клиент-сервер, в которой пользователи используют RMI (через SSL) для аутентификации.NullPointerException встречается при отправке объекта javax.security.auth.Subject по RMI
клиент вызывает метод LoginInf.login():
public interface LoginIntf extends Remote {
Subject login(String username, char[] password) throws RemoteException;
}
А на сервере, LoginImpl.login() метод реализован в виде:
@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;
}
Однако, когда на на стороне клиента, после выполнения метода LoginIntf.login(), я получаю 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]
Я получаю NPE даже без сохранения возвращаемого объекта Subject в локальной переменной и доступа к нему.
Я не могу понять причину NPE. Я не верю, что это разрешение, связанные как я нахожусь в фазе DEV и предоставил AllPermission в моем файле политики:
grant {
permission java.security.AllPermission;
};
Я знаю, что javax.security.auth.Subject реализует Serializable, так что отправка это по RMI не должны Это не проблема.
Любая помощь будет высоко оценена. Заранее спасибо!
Мне не нравится этот дизайн. Предмет должен оставаться на стороне сервера. Для этого вам следует использовать шаблон удаленного сеанса. – EJP
Спасибо за предложение EJB. Несмотря на то, что я решил свою проблему, то есть теперь могу отправлять тему с сервера на клиент, я очень хочу изучить ваши отзывы. Не могли бы вы объяснить, почему Subject должен оставаться на стороне сервера? Я новичок в JAAS, и мои аргументы в пользу отправки Субъекта клиенту состоят в том, что позже, когда пользователю нужно выйти из системы, это можно сделать, построив объект LoginContext с полученным объектом и впоследствии вызвав LoginContext.logout (). – Arthur