Greetings, dear habro-readers. Here is a continuation of a series of articles about JASIG CAS. In this part, I will tell you how to collect the CAS artifact and start working with it. Before reading further, I hope you read the
first part .
Set up, gathered ... sorted out.
As they say, the right attitude is half the battle. In order to properly configure and build your version of CAS, you need to be well aware of how Spring and Maven work.
If you want to know Tao CAS settings from beginning to end, then you
here . I will tell you about the main things that you need to know, in order to successfully run CAS in the environment that I described in the first article.
To begin, I will give a list of files that may be needed for configuration. After that, I will focus in more detail on those of them that I consider the most important. The original list can be found
here .
Configuration files
- WEB-INF / classes / log4j.xml. This file contains logging settings. If you wish, you can add your own loggers, CAS does not impose any restrictions.
- WEB-INF / cas-servlet.xml. This is the Spring MVC configuration of servlets that handle the CAS service URLs.
- WEB-INF / cas.properties. Contains URLs of utility services, SQL dialect and in general any properties that come up, you can add here.
- WEB-INF / deployerConfigContext.xml. Almost all service settings are in this file.
- WEB-INF / login-webflow.xml. Here, using Spring Web Flow, authorization flow is configured.
- WEB-INF / restlet-servlet.xml. Configuring RESTful APIs. In theory, you will never have to change this file.
- WEB-INF / classes / messages _ *. Properties. This is a set of property files used to localize CAS.
- WEB-INF / spring-configuration. In this directory are the settings of most components. Many of them can be safely redefined.
')
Configuration files located in WEB-INF / spring-configuration
- applicationContext.xml. Contains standard bins that usually do not need to be redefined, such as the Autowiring scheduler and Quartz task settings.
- ticketRegistry.xml. Register of tickets. You hardly want to change it.
- argumentExtractorsConfiguration.xml. Responsible for the choice of protocol. The default is CAS and SAML.
- propertyFileConfigurer.xml. Specifies the path where to get the properties. By defaulting from WEB-INF / cas.properties
- securityContext.xml.
- ticketExpirationPolicies.xml. Settings related to the creation and validation of tickets.
- ticketGrantingTicketCookieGenerator.xml. Describes how to create a TGT. Most likely it will not be necessary to change it.
deploymentconfigContext.xml
And so, the key CAS configuration file is deployerConfigContext.xml. This file is quite voluminous, so I will disassemble it in parts from top to bottom.
At the very beginning of the file is a list of credential resolvers. Resolvers are responsible for retrieving credentials from an authorization request that arrives at the server.
<property name="credentialsToPrincipalResolvers"> ... </property>
If you will not use anything other than the login / password transmitted from the authorization form, then this section can be safely left as is.
Next is a description of the handlers who are responsible for how CAS will use the credentials obtained. I use them to search a user in 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>
IMPORTANT! In the product environment, be sure to remove the SimpleTestUsernamePasswordAuthenticationHandler .
IMPORTANT! Pay attention to the p parameter : timeout = "$ {ldapReadConnectTimeout}" . This is a read / connect timeout with LDAP. Without setting this parameter, the standard values will not be overwritten, despite, even, the set parameters com.sun.jndi.ldap.connect.timeout com.sun.jndi.ldap.read.timeout, which will be discussed later.
The next block of configurations is related to setting up a user data source. I will give an example configuration when users are stored in openLdap.
There are two ways to search for users in LDAP:
- FastBindLdapAuthenticationHandler. It is the fastest, but it is suitable only in cases where the distinguished name can be directly built from the credentials, i.e. uid =% u, ou = users, dc = domain. Where% u is the login that was passed.
- BindLdapAuthenticationHandler. It is slightly slower, but allows more freedom in choosing the desired record. It works in 2 stages - the LDAP bind starts from the beginning. Accounting for bind is taken from the contextSource, which I will talk about later. Stage 2 - LDAP search using a filter.
IMPORTANT! When working with LDAP, base, for search and bind operations is used differently. For bind, you always need to specify the full name of the entry, that is, for example, cn = user, dc = sso, dc = ru, where base is dc = sso, dc = ru. Therefore, the base in the contextSource setting must always be filled in and userDN is always the full name of the user, under which CAS is authorized in LDAP.
During the search, searchBase is added to the search filter to limit the scan area. It may well be empty, in this case the search criteria in the directory is determined only by the filter.
An example of setting 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>
Parameters com.sun.jndi.ldap. (Connect, read) .timeout are responsible for timeouts when connecting and reading data from LDAP, respectively.
There should be no problems with userDetailsService, so we’ll go straight to the last important setting - the service repository. There are several ways to store registered services. The default is inMemory repository. This option is not suitable for the product environment and for those cases when you want to share one list of services among several CAS servers. We use MySql, deployed, on the same machine as the CAS server. If this option is acceptable for you, you can simply copy this configuration and substitute your username / password.
<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=""/>
ticketExpirationPolicies.xml
This is another important configuration file. It describes expiration policies for ST and TGT. You may need to increase the parameter values for ST, if you are going to change the protocol of interaction, there are serious network delays or the servers participating in SSO are not synchronized in time.
cas.properties
There are not so many standard properties here.
cas.securityContext.serviceProperties.service. Its value can be for example https: // localhost: 8443 / cas / services / j_acegi_cas_security_check. This is the URL of the servlet that performs ticket checks. Here it looks like this: We prefer to make this and many other settings in the properties of MAVEN profiles and substitute them during assembly. How this is done, I will tell you later.
cas.securityContext.serviceProperties.adminRoles = ROLE_ADMIN. This property contains the names of user roles from Spring Security. Users with these roles have access to the CAS service interfaces. This setting is directly related to userDetailsService from deployerConfigContext.xml.
cas.securityContext.casProcessingFilterEntryPoint.loginUrl. Along this path is a servlet that accepts user credentials.
cas.securityContext.ticketValidator.casServerUrlPrefix. CAS URL.
host.name. As I understand it, this parameter is mainly used as a prefix in the TGT and ST names. So you can choose any name for your taste.
database.hibernate.dialect. This property defines the SQL dialect of Hibernate. In deployerConfigContext.xml, we selected MySQl for storing services, respectively, its value should be set to org.hibernate.dialect.MySQLDialect.
CAS allows you to set different designs for your web interfaces using CAS themes. How this is done, I will tell, probably in another article. Details about the topics you can read
here .
Assembly
Now that you've figured out the settings, you can try to collect your own artifact. We will collect using
Maven war overlay
To begin, let us describe the properties that we need later.
<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>
Important! Be sure to specify the resource encoding that will be used when building the project. Otherwise, you may have problems with the Russian text.
Add dependencies to the project according to the settings made in 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> <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>
Building with overlay is suitable when you do not need profiles and resource filters, but you want to use the resources of another project as a base for your build.
For example, if you need to replace deployerConfigContext.xml and cas.properties, in an artifact, you can do it like this ...
<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>
Although this method is pretty good, I still recommend using
profiles . They provide much more freedom in configuring the application. With their help, for example, it is very easy to organize the assembly of artifacts for grocery and test environments.
Now the build tag will look like this
<plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <warName>cas</warName> <webResources> <resource> <directory>src/main/config</directory> <targetPath>WEB-INF</targetPath> <filtering>true</filtering> </resource> </webResources> </configuration> </plugin>
Now add profiles
<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>
In a tag of profiles it is reasonable to carry out all properties which differ in different environments.
Now you can create the / src / main / config directory and copy there all the resources for which you want to filter using Maven. As a result, the structure of your project may look something like the one shown on the right.
It remains only to collect the project, for example for the product environment ...
mvn -e clean compile package -P prod
The modifier —e instructs to show more detailed information about the build process, including the stacktrace of any error that occurs.
Important! Before building, make sure that for all the locales in which you intend to use CAS, all messages are present. To do this, you need to make sure that the message file for the necessary locales contains the same messages as the file for the en locale. If this is not the case, you need to copy the recource Bundle to your project in the / webapp / WEB-INF / classes / directory and manually add the message list. Otherwise, CAS will not be able to display any service interface in which the necessary messages are missing.
We take off
Well, CAS is built and running, and the last step separates us from the full-fledged unified authorization service - adding trusted services. Detailed instructions on how to do this can be
found here .
Important! The first service, must be added to the CAS itself. If this is not done, after adding any other service, the service interfaces will become unavailable and you will most likely have to manually clear the service repository or add CAS to it.
To add a service to CAS, go to the services management page at https: // $ {serverUrl} /services/add.html. Get access to this page, can only authorized users. User roles are configured in cas.properties and deployerConfigContext.xml.
Service URLs support ANT-style templating. For example, to add to the trusted all services located on the local machine, you can use this pattern - ht tp *: // localhost: * / **.
That's all for this time. In the third part, I will tell you how to deal with some common problems, optimize performance and log in from external forms, and even asynchronously.
Thank you for reading to the end)