...
This document describes how to enable authentication via X.509 certificates. It supplements the official Acegi Security documentation on this subject. This kind of authentication takes place when (1) using HTTPS and (2) the server requires a client certificate. Normally when an HTTPS connection is established, only the server provides a certificate. Additionally, the server can require the client to also present a certificate. This is called mutual authentication, or two way SSL authentication.
...
- Prepare the certificate authority (CA) certificate.
- Generate the CA private key.
- Generate the self-signed certificate for the CA using the CA private key.
- Prepare the server certificate.
- Generate the server private key.
- Generate the server certificate signing request (CSR).
- Sign the server CSR using the CA private key and CA certificate.
- Prepare the client certificate.
- Generate the client private key.
- Generate the client CSR.
- Sign the client CSR using the CA private key and CA certificate.
- Import the CA certificate into the keystore (e.g.
cacerts
) containing the root certificates of certificate authorities.- Export the CA private key and CA certificate into a format suitable for the JVM keystore.
- Import the CA private key and CA certificate into a temporary keystore.
- Export the CA certificate out of the temporary keystore.
- Import the CA certificate into the
cacerts
file.
- Import the server private key and server certificate into the keystore to be used by the server.
- Export the server private key and server certificate into a format suitable for the server keystore.
- Import the server private key and server certificate into the server keystore.
- Edit the server config to enable HTTPS and to use the server keystore.
- Import the client private key and client certificate into the browser.
- Export the client private key and client certificate into a format suitable for the browser.
- Import the client private key and client certificate into the browser.
- Modify the Pentaho BI Server security configuration to handle client certificates.
Results
Examples
Example using OpenSSL
The example below assumes the presence of the OpenSSL toolkit. Most Linux distributions come with OpenSSL. For Windows, there are a pre-compiled binaries.
Panel | ||
---|---|---|
| ||
# Generate the CA private key. You will be prompted for a key password. # Generate the self-signed certificate for the CA using the CA private key. |
Panel | ||
---|---|---|
| ||
# Generate the server private key. You will be prompted for a key password. # Generate the server certificate signing request (CSR). # Sign the server CSR using the CA private key and CA certificate. |
Panel | ||
---|---|---|
| ||
# Generate the client private key. # Generate the client CSR. # Sign the client CSR using the CA private key and CA certificate. |
Panel | ||
---|---|---|
| ||
# Export the CA private key and CA certificate into a format suitable for the JVM keystore. # Import the CA private key and CA certificate into a temporary keystore. # Export the CA certificate out of the temporary keystore. # Import the CA certificate into the cacerts file. |
Panel | ||
---|---|---|
| ||
# Export the server private key and server certificate into a format suitable for the server keystore. # Import the server private key and server certificate into the server keystore. |
Panel | ||
---|---|---|
| ||
# Edit the server config to enable HTTPS and to use the server keystore. |
Panel | ||
---|---|---|
| ||
# Export the client private key and client certificate into a format suitable for the browser. # Import the client private key and client certificate into the browser. |
Code Block | ||
---|---|---|
| ||
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- ======================== FILTER CHAIN ======================= -->
<!--
if you wish to use channel security, add "channelProcessingFilter," in front of
"httpSessionContextIntegrationFilter" in the list below
-->
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value><![CDATA[CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=channelProcessingFilter,securityContextHolderAwareRequestFilter,httpSessionContextIntegrationFilter, \
httpSessionReuseDetectionFilter,logoutFilter,x509ProcessingFilter,anonymousProcessingFilter, \
pentahoSecurityStartupFilter,exceptionTranslationFilter,filterInvocationInterceptor]]>
</value>
</property>
</bean>
<!-- ======================== AUTHENTICATION ======================= -->
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="x509AuthenticationProvider" />
<ref local="anonymousAuthenticationProvider" />
</list>
</property>
</bean>
<!-- Automatically receives AuthenticationEvent messages -->
<bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener" />
<bean id="pentahoSecurityStartupFilter" class="com.pentaho.security.SecurityStartupFilter" />
<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="key" value="foobar" />
<property name="userAttribute" value="anonymousUser,Anonymous" />
</bean>
<bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key" value="foobar" />
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
<property name="context" value="org.acegisecurity.context.SecurityContextImpl" />
</bean>
<bean id="x509AuthenticationProvider" class="org.acegisecurity.providers.x509.X509AuthenticationProvider">
<property name="x509AuthoritiesPopulator">
<ref local="x509AuthoritiesPopulator" />
</property>
</bean>
<bean id="x509AuthoritiesPopulator" class="org.acegisecurity.providers.x509.populator.DaoX509AuthoritiesPopulator">
<property name="userDetailsService">
<ref bean="userDetailsService" />
</property>
</bean>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp" />
<constructor-arg>
<list>
<bean class="com.pentaho.security.ProPentahoLogoutHandler" />
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
<property name="filterProcessesUrl" value="/Logout" />
</bean>
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />
<bean id="httpSessionReuseDetectionFilter" class="com.pentaho.security.HttpSessionReuseDetectionFilter">
<property name="filterProcessesUrl" value="/j_acegi_security_check" />
<property name="sessionReuseDetectedUrl" value="/Login?login_error=2" />
</bean>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
<!-- Enabled by default for X.509 (obviously) -->
<bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter">
<property name="channelDecisionManager">
<ref local="channelDecisionManager" />
</property>
<property name="filterInvocationDefinitionSource">
<value>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A.*\Z=REQUIRES_SECURE_CHANNEL</value>
</property>
</bean>
<bean id="channelDecisionManager" class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">
<property name="channelProcessors">
<list>
<ref local="secureChannelProcessor" />
<ref local="insecureChannelProcessor" />
</list>
</property>
</bean>
<bean id="secureChannelProcessor" class="org.acegisecurity.securechannel.SecureChannelProcessor" />
<bean id="insecureChannelProcessor" class="org.acegisecurity.securechannel.InsecureChannelProcessor" />
<!-- ===================== HTTP REQUEST SECURITY ==================== -->
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<ref local="x509ProcessingFilterEntryPoint" />
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl" />
</property>
</bean>
<bean id="x509ProcessingFilter" class="org.acegisecurity.ui.x509.X509ProcessingFilter">
<property name="authenticationManager">
<ref local="authenticationManager" />
</property>
</bean>
<bean id="x509ProcessingFilterEntryPoint" class="org.acegisecurity.ui.x509.X509ProcessingFilterEntryPoint">
</bean>
<bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false" />
<property name="decisionVoters">
<list>
<ref bean="roleVoter" />
</list>
</property>
</bean>
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager">
<ref local="authenticationManager" />
</property>
<property name="accessDecisionManager">
<ref local="httpRequestAccessDecisionManager" />
</property>
<property name="objectDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/public/.*\Z=Anonymous,Authenticated
\A/login.*\Z=Anonymous,Authenticated
\A/j_acegi_security_check.*\Z=Anonymous,Authenticated
\A/getmondrianmodel.*\Z=Anonymous,Authenticated
\A/getimage.*\Z=Anonymous,Authenticated
\A/getresource.*\Z=Anonymous,Authenticated
\A/admin.*\Z=Admin
\A/auditreport.*\Z=Admin
\A/auditreportlist.*\Z=Admin
\A/versioncontrol.*\Z=Admin
\A/propertieseditor.*\Z=Admin
\A/propertiespanel.*\Z=Admin
\A/subscriptionadmin.*\Z=Admin
\A/resetrepository.*\Z=Admin
\A/viewaction.*solution.admin.*\Z=Admin
\A/scheduleradmin.*\Z=Admin
\A/publish.*\Z=Admin
\A/logout.*\Z=Anonymous
\A/.*\Z=Authenticated
]]>
</value>
</property>
</bean>
</beans>
|