Выйти с помощью модуля входа в систему JAAS - PullRequest
0 голосов
/ 11 марта 2020

Вопрос немного длиннее, чем ожидалось, поэтому вот ссылка на похожий вопрос (3-ий пост), где я не нашел ответ удовлетворительным.

TL; DR

Я пытаюсь выйти из системы с помощью модуля входа в систему JAAS. Вот краткая структура проекта: LoginService отвечает за создание экземпляра LoginContext, когда пользователь хочет войти:

@Service
public class LoginService {

    public UserDTO getUserDTOFrom(Credentials credentials) {
        try {
            LoginContext loginContext = new LoginContext("Login", new JAASCallbackHandler(credentials));
            loginContext.login();
            // construct UserDTO object.
        } catch (LoginException e) {
            LOGGER.error("Login Exception: {}", e.getMessage());
            // construct UserDTO object.
        }
    // return UserDTO object.
}

Этот метод вызывается LoginController:

@RestController
@RequestMapping("/login")
public class LoginController {

    private final LoginService loginService;

    @Autowired
    public LoginController(LoginService loginService) {
        this.loginService = loginService;
    }

    @PostMapping
    public ResponseEntity<UserDTO> getUserDTOFrom(@Valid @RequestBody Credentials credentials) {
        UserDTO userDTO = loginService.getUserDTOFrom(userForm);
        // return response that depends on outcome in the login service
    }
}

Проблема возникает, когда я хочу выйти из ранее вошедшего в систему пользователя. LoginContext отвечает за вызов метода выхода из системы в JAAS Login Module. Например:

loginContext.logout();

Метод в модуле входа в систему JAAS:

public class JAASLoginModule implements LoginModule {

    @Override
    public boolean logout() {
        subject.getPrincipals().remove(usernamePrincipal);
        subject.getPrincipals().remove(passwordPrincipal);
        return true;
    }
}

У меня нет LoginContext в LogoutService и я не могу полностью очистить ранее аутентифицированный субъект.

Я попытался создать одноэлементный компонент, поэтому я смог бы получить тот же экземпляр LoginContext:

@Configuration
public class LoginContextBean {

    @Lazy
    @Bean
    public LoginContext getLoginContext(Credentials credentials) throws LoginException {
        System.setProperty("java.security.auth.login.config", "resources/configuration/jaas.config");
        return new LoginContext("Login", new JAASCallbackHandler(credentials));
    }
}

@Service
public class LoginService {

    private final ObjectProvider<LoginContext> loginContextProvider;

    @Autowired
    public LoginService(ObjectProvider<LoginContext> loginContextProvider) {
        this.loginContextProvider = loginContextProvider;
    }

    public UserDTO getUserDTOFrom(Credentials credentials) {
        try {
            LoginContext loginContext = loginContextProvider.getObject(credentials);
            loginContext.login();
            // construct UserDTO object.
        } catch (LoginException e) {
            LOGGER.error("Login Exception: {}", e.getMessage());
            // construct UserDTO object.
        }
    // return UserDTO object.
    }
}

@Service
public class LogoutService {

    private final ObjectProvider<LoginContext> loginContextProvider;

    @Autowired
    public LogoutService(ObjectProvider<LoginContext> loginContextProvider) {
        this.loginContextProvider = loginContextProvider;
    }

    public void performLogout() {
        LoginContext loginContext = loginContextProvider.getObject();
        try {
            loginContext.logout();
        } catch (LoginException e) {
            LOGGER.error("Failed to logout: {}.", e.getMessage());
        }
    }
}

Это не особенно полезно, поскольку следующий / тот же пользователь регистрируется Вы получите NPE на LoginContext. Я прочитал, что HttpServletRequest getSession (). Invalidate (); Предположим, что для вызова logout () JAAS или что выход из системы HttpServletRequest () будет делать эту работу. Но оба метода не имеют никакого эффекта. Например:

@RestController
@RequestMapping("/logout")
public class LogoutController {

    private final LogoutService logoutService;

    @Autowired
    public LogoutController(LogoutService logoutService) {
        this.logoutService = logoutService;
    }

    @DeleteMapping
    public ResponseEntity<Void> deleteJwt(@CookieValue("jwt_cookie") String jwtToken, HttpServletRequest request) throws ServletException {
        request.getSession().invalidate(); // logout() is not called.
        request.logout(); // logout() is not called.
        return getResponse();
    }
} 

Я хочу получить руку на ранее созданный LoginContext, когда пользователь хочет выйти, но создать новый, когда другой пользователь пытается войти. Обратите внимание, что я не использую Spring Security.

EDIT :

Одна из идей состояла в том, чтобы использовать синглтон, который будет содержать набор контекстов входа в систему, связанных с конкретным пользователем. А затем позвоните и уничтожьте их, когда пользователь выйдет из системы. Ключом для такого набора может быть токен jwt или userId. После дальнейших размышлений мне показалось, что пользователь может иметь несколько сеансов, и в этом случае userId в качестве ключа не сможет служить своей цели. Второй вариант - токен jwt. Но есть сценарий, когда будущее промежуточное ПО выдаст новый токен jwt по истечении срока действия, тогда мой набор не сможет вернуть действительный контекст входа в систему.

1 Ответ

0 голосов
/ 12 марта 2020

После некоторых исследований моя команда решила, что JAAS не соответствует нашим потребностям. Мы не используем полную функциональность, которую он может предложить, и это связывает наши руки, а не сглаживает процесс разработки.

Если вы столкнетесь с подобной проблемой, вот объяснение: мы используем WebSphere 8.5.5 это имеет поддержку JAAS. Можно выйти из системы, но цена будет привязана к серверу приложений. Учитывая, что в наших планах перейти от WebSphere, эта реализация не является вариантом.
Ссылка на одно из таких руководств лежит здесь .

Есть две альтернативы на будущее :

  1. Оберните его в Spring Security, поскольку он предлагает поддержку JAAS ;
  2. Замените пользовательский модуль, полностью полагаясь на функциональность Spring Security.
...