Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The example below assumes the presence of the OpenSSL toolkit. Most Linux distributions come with OpenSSL. For Windows, there are a pre-compiled binaries.

...

Prepare the certificate authority (CA) certificate.

title
Panel

# Generate the CA private key.
# You will be prompted for a key password.
openssl genrsa -des3 -out ca.key 4096

# Generate the self-signed certificate for the CA using the CA private key.
openssl req -new -x509 -days 1825 -key myca.key -out myca.crt

Panel

Prepare the server certificate.

title
Panel

# Generate the server private key.
# You will be prompted for a key password.
openssl genrsa -des3 -out server.key 4096

# Generate the server certificate signing request (CSR).
openssl req -new -key server.key -out server.csr

# Sign the server CSR using the CA private key and CA certificate.
openssl x509 -req -days 1825 -in server.csr -CA myca.crt -CAkey myca.key -set_serial 01 -out server.crt

Panel

Prepare the client certificate.

Panel

# Generate the client private key.
# You will be prompted for a key password.
openssl genrsa -des3 -out me.key 4096

# Generate the client CSR.
openssl req -new -key me.key -out me.csr

# Sign the client CSR using the CA private key and CA certificate.
openssl x509 -req -days 1825 -in me.csr -CA myca.crt -CAkey myca.key -set_serial 02 -out me.crt

Panel
title

Import the CA certificate into the keystore

...

containing the root certificates of certificate authorities.

Panel

# Export the CA private key and CA certificate into a format suitable for the JVM keystore.
openssl pkcs8 -topk8 -nocrypt -in myca.key -out myca.key.der -outform der
openssl x509 -in myca.crt -out myca.crt.der -outform der

# Import the CA private key and CA certificate into a temporary keystore.
java -Dkeystore=MyCAKeystore -cp . comu.ImportKey myca.key.der myca.crt.der

# Export the CA certificate out of the temporary keystore.
keytool -export -alias importkey -file myca.crt.jks -keystore MyCAKeystore

# Import the CA certificate into the cacerts file.
sudo keytool -import -alias mypentahoca -keystore cacerts -trustcacerts -file ~/tmp/myca.crt.jks

Panel
title

Import the server private key and server certificate into the keystore to be used by the server.

title
Panel

# Export the server private key and server certificate into a format suitable for the server keystore.
openssl pkcs8 -topk8 -nocrypt -in server.key -out server.key.der -outform der
openssl x509 -in server.crt -out server.crt.der -outform der

# Import the server private key and server certificate into the server keystore.
java -Dkeystore=TomcatKeystore -Dkeypass=changeit -cp . comu.ImportKey server.key.der server.crt.der tomcat

Panel

Edit the server config to enable HTTPS and to use the server keystore.

panel
Panel

# Edit the server config to enable HTTPS and to use the server keystore.
# Note: clientAuth="false" tells Tomcat not to prompt for a client certificate. Normally this is false, however
# you may wish to set it to true to force a prompt. This would be appropriate if clients are already submitting
# their client cert anyway.
<Connector port="8443" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS" keystoreFile="/home/mlowery/tmp/TomcatKeystore" />

title

Import the client private key and client certificate into the browser.

Panel

# Export the client private key and client certificate into a format suitable for the browser.
# In this case, Mozilla Firefox requires PKCS12 format.
openssl pkcs12 -export -out me.pkcs12 -in me.crt -inkey me.key

# Import the client private key and client certificate into the browser.
# Normally, this would be some button clicks but for Firefox 3 on Ubuntu, this workaround is required. Make sure Firefox is closed during this command.
pk12util -i me.pkcs12 -d ~/.mozilla/firefox/xxxxxxxx.default

Modify the Pentaho BI Server security configuration to handle client certificates.

Include Page
ServerDoc2x:Formatting Warning Include
ServerDoc2x:Formatting Warning Include
Code Block
titleModify the Pentaho BI Server security configuration to handle client certificates. (file=applicationContext-acegi-security.xml)
<?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>

...