Page tree

This page describe all the steps to enable Atlassian Crowd based authorization and authentication to an IHTSDO tools application using Identity Management Service.

Step-by-step guide

  1. Login to crowd interface

    In order to create application user group, user should have crowd admin role.
  2. Define a application user group(s)

    1. Create application specific group. For example WRP admin can be ihtsdo-wrp-admin. A normal WRP user can be categorize under ihtsdo-wrp-users

      This step can be skipped if application want to use default user group - ihtsdo-users for an application for authorization
  3. Add newly created group to ihtsdo-tools application as shown in image
     

  4. Enable back end security using spring security.

    1. In order to enable spring based security, application should use dependency of ihtsdo-crowd-resources and ihtsdo-crowd-bridge modules in its maven build.  An example of these is given as below.

      Authorization is specific to individual application under IHTSDO tools and application should decide how to enforce authorization to available roles to application.
      Maven Dependency
              <dependency>
      		  <groupId>org.ihtsdo.otf</groupId>
      		  <artifactId>ihtsdo-crowd-resources</artifactId>
      		  <version>x.x.x</version>
            	  <classifier>resources</classifier>
                <type>zip</type>
                <scope>provided</scope>		  
      		</dependency>
      		
      		<dependency>
      		  <groupId>org.ihtsdo.otf</groupId>
      		  <artifactId>ihtsdo-crowd-bridge</artifactId>
      		  <version>x.x.x</version>
      		</dependency>

       

       

    2. Load crowd spring bean resources application-im-common-security-config.xml and applicationContext-CrowdClient.xml. Loading can be done using both xml or java annotation way. Example is

      Crowd Spring Beans
      Xml Config
      <import resource="classpath:applicationContext-CrowdClient.xml" />, <import resource="classpath:application-im-common-security-config.xml" /> 
      or 
      Java annotation
      @ImportResource({"classpath:applicationContext-CrowdClient.xml","classpath:application-im-common-security-config.xml"})
    3.  Bundle above crowd spring bean resource files in war.

      Maven Crowd Resources Loading
              <resources>
                <resource>
                  <directory>${basedir}/src/main/resources</directory>
                </resource>
                <resource>
                  <directory>${project.build.directory}/generated-resources</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>   
      
      
      			<plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-dependency-plugin</artifactId>
                     <version>2.10</version>
                     <executions>
                       <execution>
                          <id>unpack-crowd-resources</id>
                             <goals>
                           <goal>unpack-dependencies</goal>
                             </goals>
                             <phase>generate-resources</phase>
                             <configuration>
                             <outputDirectory>${project.build.directory}/generated-resources</outputDirectory>
                             <includeGroupIds>${project.groupId}</includeGroupIds>
                             <includeArtifacIds>ihtsdo-crowd-resources</includeArtifacIds>
                             <excludeArtifactIds>*</excludeArtifactIds>
                             <excludeTransitive>true</excludeTransitive>
                             <scope>provided</scope>
                   
                            <includes>crowd.properties,
                                application-im-common-security-config.xml,
                                applicationContext-CrowdClient.xml,
                                crowd-ehcache.xml
                              </includes>
                             </configuration>
                       </execution>
                     </executions>
                   </plugin> 
    4. Enable method level security using spring security annotation or xml config.

      Method Security Configuration
      <sec:global-method-security pre-post-annotations="enabled"/>
    5. Use Method annotation or resource annotation to enforce authorization to desired role. See example in Identity Service module or Refset service module.

          

 

 

 

Error rendering macro 'contentbylabel'

parameters should not be empty

7 Comments

  1. Prashant Nema is there a documented REST API for non-Spring based applications?

  2. Prashant Nema, Adam Flinton - Are we planning on keeping the environment specific properties files in the "ihtsdo-crowd-resources" zip? This seems to prevent the same release package being used in UAT and Prod (which is our standard practice).
    Properties files here https://git.ihtsdotools.org/ihtsdo/identity-management/tree/master/ihtsdo-crowd-resources/src/main/resources

  3. no we are not. took a bit of winkling out as the code wanted to be deployed as a war but the properties etc had to be on the classpath &.....having tried almost everything within the bounds of sanity I insstead now unzip the war & add the porerties & .yml to the web-inf classes dir & then run the spring warLauncher e.g.

     

    /usr/bin/java org.springframework.boot.loader.WarLauncher --spring.profiles.active=prod

     

    done via a script called by supervisor.

  4. compare & contrast the same view with the branch set to "develop"

  5. Chris SwiresKai Kewley

    I got an exception while Spring trying to initialize the "crowdClient" bean. It's complaining that there is no method build(Lcom/google/common/cache/CacheLoader;) in com.google.common.cache.CacheBuilder. I've checked in my classpath, the version of guava is 10.0.1. In class CacheBuilder of that version, I found method 'build' that accept CacheLoader as input param. 

    Do you have any suggestion? Appreciated your help!

     

    My pom.xml:

    <dependency>
    <groupId>org.ihtsdo.otf</groupId>
    <artifactId>ihtsdo-crowd-resources</artifactId>
    <version>0.0.4</version>
    <classifier>resources</classifier>
    <type>zip</type>
    <!-- >scope>provided</scope -->
    </dependency>
    <dependency>
    <groupId>org.ihtsdo.otf</groupId>
    <artifactId>ihtsdo-crowd-bridge</artifactId>
    <version>0.0.4</version>
    <exclusions>
    <exclusion>
    <artifactId>guava</artifactId>
    <groupId>com.google.guava</groupId>
    </exclusion>
    </exclusions>
    </dependency>

    And the stack trace:

    SEVERE: StandardWrapper.Throwable
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crowdClient' defined in class path resource [applicationContext-CrowdClient.xml]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.atlassian.crowd.service.client.CrowdClient]: Factory method 'newInstance' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.common.cache.CacheBuilder.build(Lcom/google/common/cache/CacheLoader;)Lcom/google/common/cache/LoadingCache;
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:864)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:134)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.atlassian.crowd.service.client.CrowdClient]: Factory method 'newInstance' threw exception; nested exception is java.lang.NoSuchMethodError: com.google.common.cache.CacheBuilder.build(Lcom/google/common/cache/CacheLoader;)Lcom/google/common/cache/LoadingCache;
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 36 more
    Caused by: java.lang.NoSuchMethodError: com.google.common.cache.CacheBuilder.build(Lcom/google/common/cache/CacheLoader;)Lcom/google/common/cache/LoadingCache;
    at com.atlassian.crowd.integration.rest.util.JAXBContextCache.<init>(JAXBContextCache.java:23)
    at com.atlassian.crowd.integration.rest.service.RestExecutor.<init>(RestExecutor.java:87)
    at com.atlassian.crowd.integration.rest.service.RestCrowdClient.<init>(RestCrowdClient.java:86)
    at com.atlassian.crowd.integration.rest.service.factory.RestCrowdClientFactory.newInstance(RestCrowdClientFactory.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 37 more

     

    1. I have bypassed this error by adding a newer version of guava in my pom

      1. I don't find and pre-configured bean to verify token and retrieve user information. Hence I have added a custom Filter  and placed it at the top of filter chain. That filter does two things: 1. Get User object from token and 2. Create an Authentication object and save to SecurityContextHolder. 

        To load/save authentication object, I wrote a SecurityContextRepository. It read the Authentication object in its load method.

        Spring-security configuration:

        <import resource="classpath:application-im-common-security-config.xml" />
        <import resource="classpath:applicationContext-CrowdClient.xml" />

        <s:global-method-security pre-post-annotations="enabled"/>

        <s:http pattern="/api/**" create-session="stateless" auto-config="false" entry-point-ref="restAuthenticationEntryPoint" security-context-repository-ref="securityContextHolder">
            <s:custom-filter ref="tokenTaker" position="FIRST"/>
            <security:access-denied-handler error-page="/error/401"/>
            <s:intercept-url pattern="/api/project/topsecret" access="ROLE_ihtsdo-ops-admin" />
            <s:intercept-url pattern="/api/project/**" access="ROLE_ihtsdo-sca-author" />
        </s:http>
        <s:http pattern="/error/**" security="none" />

        <bean id="tokenTaker" class="org.ihtsdotools.crs.filter.TokenFilter">
            <constructor-arg name="userService" ref="crowdUserDetailsService"/>
        </bean>
        <bean id="securityContextHolder" class="org.ihtsdotools.crs.security.CrsStatelessSCRepository"/>
        <bean id="restAuthenticationEntryPoint" class="org.ihtsdotools.crs.security.RestAuthenEntryPoint" />

        org.ihtsdotools.crs.security.RestAuthenEntryPoint just set error code 401 to the response.