- PVSM.RU - https://www.pvsm.ru -
-sredstvami-JASIG-CAS-chast-2.jpg)
Приветствую, уважаемые хабро-читатели. Перед вами продолжение серии статей про JASIG CAS. В этой части я расскажу, как собрать артефакт CAS и начать с ним работать. Прежде, чем читать дальше, я надеюсь, вы прочитали первую часть [1].
Как говорится, правильный настрой — половина дела. Для того, что бы правильно сконфигурировать и собрать свою версию CAS, вы должны хорошо представлять себе, как работают Spring и Maven.
Если вы хотите познать дао настройки CAS от начала до конца, то вам вот сюда [2]. Я же расскажу про основные вещи, которые нужно знать, для того, что бы успешно запустить CAS в той среде, которую я описал в первой статье.
Для начала приведу список файлов, которые могут понадобиться для настройки. После этого, я остановлюсь подробнее на тех из них, которые считаю наиболее важными. Оригинал списка можно найти здесь [3].
И так, ключевым файлом настройки CAS является deployerConfigContext.xml. Это довольно объемный файл, поэтому я буду разбирать его частями сверху вниз.
В самом начале файла располагается список резолверов учетных данных. Резолверы отвечают за извлечение учетных данных из запроса авторизации, приходящей на сервер.
<property name="credentialsToPrincipalResolvers">
...
</property>
Если вы не будете использовать ничего, кроме логина/пароля, переданных с формы авторизации, то этот раздел можно смело оставить как есть.
Дальше идет описание обработчиков, которые отвечают за то, как CAS будет использовать полученные учетные данные. Я использую их для поиска пользователя в LDAP
<property name="authenticationHandlers">
<list>
<bean class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler"
p:filter="userLogin =%u"
p:searchBase=""
p:timeout="${ldapReadConnectTimeout}"
p:contextSource-ref="contextSource"/>
</property>
ВАЖНО! В продуктовой среде обязательно удалите SimpleTestUsernamePasswordAuthenticationHandler.
ВАЖНО! Обратите внимание на параметр p:timeout="${ldapReadConnectTimeout}". Это таймаут чтения/соединения с LDAP. Без установки этого параметра стандартные значения не будут переписаны, не смотря, даже, на установленные параметры com.sun.jndi.ldap.connect.timeout com.sun.jndi.ldap.read.timeout, о которых речь пойдет чуть позже.
Следующий блок конфигураций связан с настройкой источника данных о пользователях. Я приведу пример конфигурации, когда пользователи хранятся в openLdap.
Есть два способа поиска пользователей в LDAP:
ВАЖНО! При работе с LDAP, base, для операций search и bind используется по-разному. Для bind всегда нужно указывать полное имя записи, т.е., например cn=user,dc=sso,dc=ru, где base — dc=sso,dc=ru. Поэтому base в настройке contextSource всегда должен быть заполнен и userDN — это всегда полное имя пользователя, под которым авторизуется CAS в LDAP.
Во время поиска searchBase добавляется к фильтру поиска для ограничения области сканирования. Он вполне может быть пустым, в этом случае критерий поиска в директории определяется только фильтром.
Пример настройки contextSource.
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="pooled" value="false"/>
<property name="urls">
<list>
<value>ldap://your.host.nameORip</value>
</list>
</property>
<property name="userDn" value="cn=user,dc=subdomain,dc=domain"/>
<property name="password" value="verybigsecret"/>
<property name="base" value="dc=subdomain,dc=domain"/>
<property name="baseEnvironmentProperties">
<map>
<entry>
<key>
<value>java.naming.security.authentication</value>
</key>
<value>simple</value>
</entry>
<entry key="com.sun.jndi.ldap.connect.timeout" value="5000"/>
<entry key="com.sun.jndi.ldap.read.timeout" value="5000"/>
</map>
</property>
</bean>
Параметры com.sun.jndi.ldap.(connect, read).timeout отвечают за таймауты при соединении и чтении данных из LDAP соответственно.
С userDetailsService проблем возникнуть не должно, поэтому перейдем сразу к последней важной настройке — хранилищу сервисов. Есть несколько способов хранить зарегистрированные сервисы. По умолчанию используется inMemory хранилище. Этот вариант не подходит для продуктовой среды и тех случаев, когда вы хотите разделять один список сервисов среди нескольких CAS серверов. Мы используем MySql, развернутый, на той же машине, что и сервер CAS. Если такой вариант приемлем для вас, вы можете просто скопировать эту конфигурацию и подставить свои логинпароль.
<bean id="serviceRegistryDao"
class="org.jasig.cas.services.JpaServiceRegistryDaoImpl"
p:entityManagerFactory-ref="entityManagerFactory"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/cas?autoReconnect=true"
p:username="root"
p:password=""/>
Это еще один важный файл настройки. В нем описаны expiration policies для ST и TGT. Вам может понадобиться увеличить значения параметров для ST, если вы собираетесь изменять протокол взаимодействия, наблюдаются серьезные сетевые задержки или сервера, участвующие в SSO, плохо синхронизированы по времени.
Стандартных свойств здесь не так много.
cas.securityContext.serviceProperties.service. Значение его может быть например https:// localhost:8443/cas/services/j_acegi_cas_security_check. Это URL сервлета, который производит проверки тикетов. У нас он выглядит вот так: ${service} т.к. эту и многие другие настройки мы предпочитаем выносить в свойства MAVEN профилей и подставлять при сборке. Как это делается, я расскажу чуть позже.
cas.securityContext.serviceProperties.adminRoles=ROLE_ADMIN. Это свойство содержит названия ролей пользователей из Spring Security. Пользователи с этими ролями имеют доступ к служебным интерфейсам CAS. Эта настройка непосредственно связана с userDetailsService из deployerConfigContext.xml.
cas.securityContext.casProcessingFilterEntryPoint.loginUrl. По этому пути расположен сервлет, который принимает учетные данные пользователя.
cas.securityContext.ticketValidator.casServerUrlPrefix. URL CAS.
host.name. Как я понял, этот параметр используется в основном как префикс в именах TGT и ST. Так что можете выбрать любое название на ваш вкус.
database.hibernate.dialect. Это свойство определяет SQL диалект Hibernate. В deployerConfigContext.xml мы выбрали MySQl для хранения сервисов, соответственно его значение должно быть установлено в org.hibernate.dialect.MySQLDialect.
CAS позволяет задавать разное оформление для своих web интерфейсов, с помощью CAS themes. Как это делается, я расскажу, наверно, в другой статье. Подробно о темах можно почитать вот здесь [4].
Теперь, когда с настройками разобрались, можно попробовать собрать свой собственный артефакт. Собирать будем с помощью Maven war overlay [5]
Для начала опишем свойства, которые нам понадобятся позже
<properties>
<spring.version>3.0.4.RELEASE</spring.version>
<spring.security.version>3.0.3.RELEASE</spring.security.version>
<cas.version>3.4.8</cas.version>
<compiler.version>2.0.2</compiler.version>
<source.version>1.6</source.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
Важно! Обязательно укажите кодировку ресурсов, которая будет использована при сборке проекта. Иначе у вас могут возникнуть проблемы с русским текстом.
Добавляем в проект зависимости в соответствии с настройками, сделанными в deployerConfigContext.xml
<!— Исходный проект CAS для которого будет применен OVERLAY -->
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-webapp</artifactId>
<version>${cas.version}</version>
<type>war</type>
<scope>runtime</scope></dependency>
<!— Зависимости для работы с базой данных -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.0.Final</version>
<exclusions>
<exclusion>
<artifactId>hibernate-core</artifactId>
<groupId>org.hibernate</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.14</version>
</dependency>
</dependencies>
<!-- Зависимости для работы с LDAP-->
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-support-ldap</artifactId>
<version>${cas.version}</version>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</exclusion>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
<exclusion>
<artifactId>spring-expression</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-expression</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-expression</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
Сборка с помощью overlay подходит, когда вам не нужны профили и фильтры ресурсов, но хочется использовать ресурсы другого проекта как базу для своей сборки.
Например, если нужно заменить deployerConfigContext.xml и cas.properties, в артефакте, это можно будет сделать вот так…
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>cas</warName>
<overlays>
<overlay>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-webapp</artifactId>
<excludes>
<exclude>WEB-INF/deployerConfigContext.xml</exclude>
<exclude>WEB-INF/cas.properties</exclude>
</excludes>
</overlay>
</overlays>
</plugin>
Хотя этот способ довольно хорош я, все же, рекомендую воспользоваться профилями [6]. Они дают значительно больше свободы в конфигурировании приложения. С их помощью, например, очень просто организовать сборку артефактов для продуктовой и тестовой сред.
Теперь build тег будет выглядеть вот так
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>cas</warName>
<webResources>
<resource>
<directory>src/main/config</directory>
<!-- override the destination directory for this resource -->
<targetPath>WEB-INF</targetPath>
<!-- enable filtering -->
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
Теперь добавляем профили
<profiles>
<profile>
<id>test</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<service>
https://localhost:8443/cas/services/j_acegi_cas_security_check
</service>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<service>
https://auth.tcsbank.ru:8443/cas/services/j_acegi_cas_security_check
</service>
</properties>
</profile>
</profiles>
В тег профилей разумно выносить все свойства, которые различаются в разных средах.
-sredstvami-JASIG-CAS-chast-2-2.jpg)
Теперь можно создать директорию /src/main/config и скопировать туда все ресурсы, для которых вы хотите проводить фильтрацию с помощью Maven. В итоге структура вашего проекта может выглядеть примерно так, как показано на картинке справа.
Осталось только собрать проект, например для продуктовой среды…
mvn -e clean compile package -P prod
Модификатор —e предписывает показывать более подробную информацию о процессе сборки, включая stacktrace любой возникшей ошибки.
Важно! Перед сборкой убедитесь, что для всех локалей, в которых предполагается использовать CAS, присутствуют все сообщения. Для этого нужно убедиться, что файл сообщений messages для нужных локалей содержат те же сообщения, что и файл для локали en. Если это не так, вам нужно скопировать recource Bundle в свой проект в директорию /webapp/WEB-INF/classes/ и вручную дополнить список сообщений. Иначе CAS не сможет отобразить ни один сервисный интерфейс, в котором отсутствуют нужные сообщения.
Ну вот, CAS собран и запущен и от полноценного сервиса единой авторизации нас отделяет последний шаг — добавление доверенных сервисов. Подробную инструкцию как это сделать, можно узнать тут [7].
Важно! Первым сервисом, обязательно должен быть добавлен сам CAS. Если этого не сделать, после добавления любого другого сервиса, служебные интерфейсы станут недоступны и вам, скорее всего, придется вручную очищать хранилище сервисов или добавить в него CAS.
Для того, что бы добавить сервис в CAS нужно перейти на страницу управления сервисам по адресу https://${serverUrl}/services/add.html. Получить доступ на эту страницу, может только авторизованный пользователь. Роли для пользователей настраиваются в cas.properties и deployerConfigContext.xml.
URL сервисов поддерживают шаблонизацию в стиле ANT. Например, что бы добавить в доверенные все сервисы, расположенные на локальной машине, можно использовать вот такой паттерн — ht tp*://localhost:*/**.
Вот и все на этот раз. В 3-ей части я расскажу как бороться с некоторыми распространенными проблемами, оптимизировать производительность и авторизовываться с внешних форм и даже асинхронно.
Спасибо что дочитали до конца)
Автор: SergeyPopov
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/avtorizatsiya/10019
Ссылки в тексте:
[1] первую часть: http://habrahabr.ru/company/tcsbank/blog/142407/
[2] вот сюда: https://wiki.jasig.org/display/CASUM/Home
[3] здесь: https://wiki.jasig.org/display/CASUM/Best+Practice+-+Setting+Up+CAS+Locally+using+the+Maven2+WAR+Overlay+Method
[4] вот здесь: https://wiki.jasig.org/display/CASUM/Theme+Control
[5] Maven war overlay: http://maven.apache.org/plugins/maven-war-plugin/overlays.html
[6] профилями: http://maven.apache.org/guides/mini/guide-building-for-different-environments.html
[7] узнать тут: https://wiki.jasig.org/display/CASUM/Adding+a+New+Service
Нажмите здесь для печати.