Рубрики
Без рубрики

CAS SSO с весенней безопасностью

Узнайте, как интегрировать Центральную службу аутентификации (CAS) с Spring Security.

Автор оригинала: baeldung.

1. Обзор

В этом учебнике мы посмотрим на Центральную службу аутентификации Apereo (CAS) и посмотрим, как служба Spring Boot может использовать ее для проверки подлинности. CAS является предприятием Единый знак-on (SSO) решение, которое также является открытым исходным кодом.

2. Настройка сервера CAS

2.1. Установка и зависимость CAS

Сервер использует стиль Военной накладки Maven (Gradle) для облегчения настройки и развертывания:

git clone https://github.com/apereo/cas-overlay-template.git cas-server

Эта команда будет клонировать cas-наложение-шаблон в cas-сервер каталог.

Некоторые из аспектов, которые мы будем охватывать включают JSON регистрации услуг и JDBC подключения базы данных. Итак, мы добавим их модули в зависимостей раздел build.gradle файл:

compile "org.apereo.cas:cas-server-support-json-service-registry:${casServerVersion}"
compile "org.apereo.cas:cas-server-support-jdbc:${casServerVersion}"

Давайте обязательно проверим последнюю версию casServer .

2.2. Конфигурация сервера CAS

Прежде чем мы сможем начать сервер CAS, нам нужно добавить некоторые основные конфигурации. Начнем с создания cas-сервер/src/main/resources папку и в этой папке. За этим последует создание application.properts в папке тоже:

server.port=8443
spring.main.allow-bean-definition-overriding=true
server.ssl.key-store=classpath:/etc/cas/thekeystore
server.ssl.key-store-password=changeit

Давайте приступить к созданию файла ключ-магазина, на который ссылаются в конфигурации выше. Во-первых, нам нужно создать папки /etc/cas и /etc/cas/config в cas-сервер/src/main/resources .

Затем нам нужно изменить каталог на cas-сервер/src/main/resources/etc/cas и запустить команду для генерации thekeystore :

keytool -genkey -keyalg RSA -alias thekeystore -keystore thekeystore -storepass changeit -validity 360 -keysize 2048

Для того, чтобы у нас не было ошибки рукопожатия SSL, мы должны использовать localhost как значение первой и фамилии. Мы должны использовать то же самое для названия организации и подразделения, а также. Кроме того, мы должны импортировать thekeystore в JDK/JRE мы будем использовать для запуска нашего клиент-приложения:

keytool -importkeystore -srckeystore thekeystore -destkeystore $JAVA11_HOME/jre/lib/security/cacerts

Пароль для магазина ключей источника и назначения changeit . В системах Unix нам, возможно, придется запускать эту команду с привилегией admin ( sudo ) ). После импорта мы должны перезапустить все экземпляры Java, которые работают или перезапустить систему.

Мы используем JDK11, потому что этого требует версия CAS 6.1.x. Кроме того, мы определили переменную по окружающей среде $JAVA 11-HOME, которая указывает на его домашний каталог. Теперь мы можем начать сервер CAS:

./gradlew run -Dorg.gradle.java.home=$JAVA11_HOME

Когда приложение запускается, мы увидим “READY” напечатаны на терминале и сервер будет доступен в https://localhost:8443 .

2.3. Конфигурация пользователя сервера CAS

Мы пока не можем войти в систему, так как не настроили пользователя. CAS имеет различные методы управление , включая автономный режим. Давайте создадим папку для cas-сервер/src/main/resources/etc/cas/config в котором мы создадим файл свойств cas.properties . Теперь мы можем определить статического пользователя в файле свойств:

cas.authn.accept.users=casuser::Mellon

Мы должны сообщить о местонахождении папки config серверу CAS для вхождения настроек в силу. Давайте обновим tasks.gradle так что мы можем передать местоположение в качестве аргумента JVM из командной строки:

task run(group: "build", description: "Run the CAS web application in embedded container mode") {
    dependsOn 'build'
    doLast {
        def casRunArgs = new ArrayList<>(Arrays.asList(
          "-server -noverify -Xmx2048M -XX:+TieredCompilation -XX:TieredStopAtLevel=1".split(" ")))
        if (project.hasProperty('args')) {
            casRunArgs.addAll(project.args.split('\\s+'))
        }
        javaexec {
            main = "-jar"
            jvmArgs = casRunArgs
            args = ["build/libs/${casWebApplicationBinaryName}"]
            logger.info "Started ${commandLine}"
        }
    }
}

Затем мы сохранить файл и запустить:

./gradlew run
  -Dorg.gradle.java.home=$JAVA11_HOME
  -Pargs="-Dcas.standalone.configurationDirectory=/cas-server/src/main/resources/etc/cas/config"

Обратите внимание, что стоимость cas.standalone.configurationПрямая это абсолютный путь . Теперь мы можем пойти https://localhost:8443 и войти в систему с именем пользователя casuser и пароль Меллон .

3. Настройка клиента CAS

Мы будем использовать Весенний инициализр для создания клиенто-приложения Spring Boot. Это будет Веб , Охрана , Фримаркер и ДевТулс Зависимости. Кроме того, мы также добавим зависимость для Весенняя безопасность CAS модуль к своему пом.xml :


    org.springframework.security
    spring-security-cas
    5.3.0.RELEASE

Наконец, давайте добавим следующие свойства Spring Boot для настройки приложения:

server.port=8900
spring.freemarker.suffix=.ftl

4. Регистрация серверов CAS

Заявки клиентов должны зарегистрироваться на сервере CAS до любого процесса проверки . Сервер CAS поддерживает использование клиентских реестров YAML, JSON, MongoDB и LDAP.

В этом учебнике мы будем использовать метод реестра услуг JSON. Давайте создадим еще одну папку cas-сервер/src/main/resources/etc/cas/services . Именно эта папка будет в реестре услуг JSON файлов.

Мы создадим файл JSON, содержащий определение нашего клиент-приложения. Название файла, casSecuredApp-8900.json, следует шаблону s erviceName-Id.json :

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "http://localhost:8900/login/cas",
  "name" : "casSecuredApp",
  "id" : 8900,
  "logoutType" : "BACK_CHANNEL",
  "logoutUrl" : "http://localhost:8900/exit/cas"
}

serviceId атрибут определяет шаблон URL-адреса regex для приложения клиента. Шаблон должен соответствовать URL-адресу приложения клиента.

id атрибут должен быть уникальным. Другими словами, не должно быть двух или более служб с одинаковыми id зарегистрирован на тот же сервер CAS. После дублирования id приведет к конфликтам и переопределению конфигураций.

cas.serviceRegistry.initFromJson=true
cas.serviceRegistry.json.location=classpath:/etc/cas/services

5. Cas Клиент Единый знак-на конфигурации

Следующим шагом для нас является настройка Spring Security для работы с сервером CAS. Мы также должны проверить полный поток взаимодействий , называется cas последовательности.

Давайте добавим следующие конфигурации фасоли в CasSecuredПрименение класс нашего приложения Весенняя загрузка:

@Bean
public CasAuthenticationFilter casAuthenticationFilter(
  AuthenticationManager authenticationManager,
  ServiceProperties serviceProperties) throws Exception {
    CasAuthenticationFilter filter = new CasAuthenticationFilter();
    filter.setAuthenticationManager(authenticationManager);
    filter.setServiceProperties(serviceProperties);
    return filter;
}

@Bean
public ServiceProperties serviceProperties() {
    logger.info("service properties");
    ServiceProperties serviceProperties = new ServiceProperties();
    serviceProperties.setService("http://cas-client:8900/login/cas");
    serviceProperties.setSendRenew(false);
    return serviceProperties;
}

@Bean
public TicketValidator ticketValidator() {
    return new Cas30ServiceTicketValidator("https://localhost:8443");
}

@Bean
public CasAuthenticationProvider casAuthenticationProvider(
  TicketValidator ticketValidator,
  ServiceProperties serviceProperties) {
    CasAuthenticationProvider provider = new CasAuthenticationProvider();
    provider.setServiceProperties(serviceProperties);
    provider.setTicketValidator(ticketValidator);
    provider.setUserDetailsService(
      s -> new User("[email protected]", "Mellon", true, true, true, true,
      AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
    provider.setKey("CAS_PROVIDER_LOCALHOST_8900");
    return provider;
}

СервисПредложение фасоль имеет тот же URL, что и serviceId в casSecuredApp-8900.json . Это важно, поскольку идентифицирует этого клиента на сервере CAS.

отправитьРенью имущество СервисПредложение установлен на ложные . Это означает, что пользователю нужно представить учетные данные входа на сервер только один раз.

АутентификацияEntryPoint боб будет обрабатывать исключения проверки подлинности. Таким образом, он перенаправит пользователя на URL-адрес сервера CAS для проверки подлинности.

Таким образом, поток аутентификации идет:

  1. Пользователь пытается получить доступ к безопасной странице, что вызывает исключение проверки подлинности
  2. Исключение вызывает АутентификацияEntryPoint . В ответ АутентификацияEntryPoint приведет пользователя на страницу входа на сервер CAS – https://localhost:8443/login
  3. При успешной аутентификации сервер перенаправляет обратно клиенту билет
  4. CasAuthenticationFilter будет забрать перенаправить и позвонить CasAuthenticationПровид
  5. CasAuthenticationПровид будет использовать TicketValidator для подтверждения представленного билета на сервере CAS
  6. Если билет действителен, пользователь получит перенаправление на запрошенный защищенный URL

Наконец, давайте настраивать HttpSecurity для обеспечения безопасности некоторых маршрутов в WebSecurityКонфиг . В процессе мы также добавим точку входа проверки подлинности для обработки исключений:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers( "/secured", "/login") 
      .authenticated() 
      .and().exceptionHandling() 
      .authenticationEntryPoint(authenticationEntryPoint());
}

6. Конфигурация клиента CAS Single Logout

До сих пор мы имели дело с одним знаком; давайте теперь рассмотрим CAS одного логотипа (SLO).

Приложения, которые используют CAS для управления аутентификацией пользователей, могут выйти из системы пользователя из двух мест:

  • Клиентское приложение может логотип пользователя от себя локально – это не повлияет на статус входа пользователя в других приложениях, использующих тот же сервер CAS
  • Клиентское приложение также может выйти из пользователя с сервера CAS – это приведет к тому, что пользователь будет выйти из всех других клиентских приложений, подключенных к тому же серверу CAS.

Сначала мы ввестим логотип в клиентское приложение, а затем распространим его на единый логотип на сервере CAS.

Для того, чтобы сделать очевидным, что происходит за кулисами, мы создадим логоут () метод обработки локального логотипа. На успех, он перенаправит нас на страницу со ссылкой на один логотип:

@GetMapping("/logout")
public String logout(
  HttpServletRequest request, 
  HttpServletResponse response, 
  SecurityContextLogoutHandler logoutHandler) {
    Authentication auth = SecurityContextHolder
      .getContext().getAuthentication();
    logoutHandler.logout(request, response, auth );
    new CookieClearingLogoutHandler(
      AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY)
      .logout(request, response, auth);
    return "auth/logout";
}

В рамках единого процесса логоса сервер CAS сначала истекает срок действия билета пользователя, а затем отправляет запрос async во все зарегистрированные клиентские приложения. Каждое клиентское приложение, которое получает этот сигнал, будет выполнять локальный логотип. Таким образом, достижение цели logout один раз, это вызовет журнал во всем мире.

Сказав это, давайте добавим некоторые конфигурации фасоли в наше клиентское приложение. В частности, в CasSecuredApplicaiton :

@Bean
public SecurityContextLogoutHandler securityContextLogoutHandler() {
    return new SecurityContextLogoutHandler();
}

@Bean
public LogoutFilter logoutFilter() {
    LogoutFilter logoutFilter = new LogoutFilter("https://localhost:8443/logout",
      securityContextLogoutHandler());
    logoutFilter.setFilterProcessesUrl("/logout/cas");
    return logoutFilter;
}

@Bean
public SingleSignOutFilter singleSignOutFilter() {
    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
    singleSignOutFilter.setCasServerUrlPrefix("https://localhost:8443");
    singleSignOutFilter.setLogoutCallbackPath("/exit/cas");
    singleSignOutFilter.setIgnoreInitConfiguration(true);
    return singleSignOutFilter;
}

logoutFilter будет перехватывать запросы на /логот/cas и перенаправить приложение на сервер CAS. SingleSignOutFilter будет перехватывать запросы, поступающие с сервера CAS, и выполнять локальный логотип.

7. Подключение сервера CAS к базе данных

Мы можем настроить сервер CAS для чтения учетных данных из базы данных MyS’L. Мы будем использовать тестовый база данных сервера MyS’L, которая работает в локальной машине. Давайте обновим cas-сервер/src/main/resources/etc/cas/config/cas.properts :

cas.authn.accept.users=

cas.authn.jdbc.query[0].sql=SELECT * FROM users WHERE email = ?
cas.authn.jdbc.query[0].url=
  jdbc:mysql://127.0.0.1:3306/test?
  useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=root
cas.authn.jdbc.query[0].ddlAuto=none
cas.authn.jdbc.query[0].driverClass=com.mysql.cj.jdbc.Driver
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].passwordEncoder.type=NONE

Мы устанавливаем cas.authn.accept.users пустой. Это позволит деактивировать использование статических репозиториев пользователей сервером CAS.

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

Пожалуйста, убедитесь, что проверить список поддерживаемых баз данных, доступных драйверов и диалектов . Мы также устанавливаем тип кодера пароля для НИКОГДА . Другие механизмы шифрования и их своеобразные свойства также доступны.

Обратите внимание, что основной в базе данных сервера CAS должен быть таким же, как и у приложения клиента.

Давайте обновим CasAuthenticationПровид иметь то же имя пользователя, что и сервер CAS:

@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
    CasAuthenticationProvider provider = new CasAuthenticationProvider();
    provider.setServiceProperties(serviceProperties());
    provider.setTicketValidator(ticketValidator());
    provider.setUserDetailsService(
      s -> new User("[email protected]", "Mellon", true, true, true, true,
      AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
    provider.setKey("CAS_PROVIDER_LOCALHOST_8900");
    return provider;
}

CasAuthenticationПровид не использует пароль для проверки подлинности. Тем не менее, его имя пользователя должно соответствовать имя сервера CAS для проверки подлинности, чтобы быть успешным. Сервер CAS требует, чтобы сервер MyS’L localhost в портовых 3306 . Имя пользователя и пароль должны быть корневые .

Перезапустив сервер CAS и приложение Spring Boot еще раз. Затем используйте новые учетные данные для проверки подлинности.

8. Заключение

Мы рассмотрели, как использовать CAS SSO с Spring Security и многие из файлов конфигурации участие. Есть много других аспектов CAS SSO, который настраивается. От тем и типов протоколов до политик аутентификации.

Эти и другие находятся в документы . Исходный код для Сервер cas и Весенняя загрузка приложение доступен на GitHub.