Я нашел решение, чтобы получить клиент, зарегистрированный в качестве UserPrincipal сессии, доступного по session.getUserPrincipal()
.
UserPricipal является «аутентифицированным пользователем для сеанса». Вы Nneed затем добавить службу Аутентификации к вашему ServletContextHandler, следующим образом:
//Create SSL ContextFactory with appropriate attributes
...
//Create the connector
...
//Create ContextHandler
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/example");
//Add security contraint to the context => authentication
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
Constraint constraint = new Constraint();
constraint.setName("auth");
constraint.setAuthenticate(true);
constraint.setRoles(new String[]{"user"});
Set<String> knownRoles = new HashSet<String>();
knownRoles.add("user");
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/*");
mapping.setConstraint(constraint);
security.setConstraintMappings(Collections.singletonList(mapping), knownRoles);
security.setAuthMethod("CLIENT-CERT");
LoginService loginService = new HashLoginService();
security.setLoginService(loginService);
security.setAuthenticator(new ClientCertAuthenticator());
context.setSecurityHandler(security);
Таким образом, когда клиент подключается к WebSocket конечной точке, обработчик безопасности гарантирует, что клиент должен пройти проверку подлинности. Как я понял, ClientCertAuthenticator проверяет клиентский запрос на извлечение информации (DN сертификата), а затем передает его в LoginService, где клиент аутентифицирован, и UserPricipal из набора сеансов.
Проблема заключается в том, что у вас должен быть действующий loginService (например, HashLoginService - это встроенная в систему учетная запись с паролями и именами пользователей, JDBCLoginService работает с базой данных). Для тех, кто, как и я, просто хочу извлечь необходимую информацию из сертификата и выполнить проверку подлинности после этой информации, вы можете предоставить свою собственную реализацию интерфейса LoginService.
Вот что я сделал:
При определении обработчика безопасности:
LoginService loginService = new CustomLoginService();
loginService.setIdentityService(new DefaultIdentityService());
security.setLoginService(loginService);
CustomLoginService класса
public class CustomLoginService implements LoginService {
IdentityService identityService = null;
@Override
public String getName() {
return "";
}
@Override
public UserIdentity login(String username, Object credentials) {
//you need to return a UserIdentity, which takes as argument:
// 1. A Subjet, containing a set of principals, a set of private credentials and a set of public ones (type Object)
// 2. A Principal of this Subject
// 3. A set of roles (String)
LdapPrincipal principal = null;
try {
principal = new LdapPrincipal(username);
//you need to have a Principal. I chose LDAP because it is specifically intended for user identified with a DN.
} catch (InvalidNameException e) {
e.printStackTrace();
}
String[] roles = new String[]{"user"};
return new DefaultUserIdentity(
new Subject(false,
new HashSet<LdapPrincipal>(Arrays.asList(new LdapPrincipal[]{principal})),
new HashSet<Object>(Arrays.asList(new Object[]{credentials})),
new HashSet<Object>(Arrays.asList(new Object[]{credentials}))),
principal,
roles);
}
@Override
public boolean validate(UserIdentity user) {
return false;
}
@Override
public IdentityService getIdentityService() {
return identityService;
}
@Override
public void setIdentityService(IdentityService service) {
identityService = service;
}
@Override
public void logout(UserIdentity user) {
}
И вот это :)
Привет, у вас есть образец рабочего проекта по этому вопросу? Я пытаюсь развернуть сервер websocket, и мне также нужно извлечь клиентский сертификат. Мне не повезло, что он работает так, как вы описали. – user1563721