Multi tenancy configuration Spring Security

Splash Forums Rewrite Users Multi tenancy configuration Spring Security

This topic contains 5 replies, has 2 voices, and was last updated by  fkoentopp 1 year, 10 months ago.

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #26378

    fkoentopp
    Participant

    Hello,

    how to do the following (I tried nearly everything, but without conclusion):

    I have a multi tenancy app, where the tenant is defined by the url, e. g. /{tenant}/xyz. Those requests should by internally mapped to /pages/xyz. For the outbound direction it should be the reverse instead, e.g. /pages/xyz to /{tenant}/xyz, so that the browser always shows the URL with the tenant. Can you give me a short hint on how to do that. Sounds easy but I can’t get it to work.

    Additional info: The app is secured with Spring Security and I have the following filter configuration:

     
    ...
    <filter>
        <filter-name>rewriteFilter</filter-name>
        <filter-class>org.ocpsoft.rewrite.servlet.RewriteFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>rewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ASYNC</dispatcher>
        <dispatcher>ERROR</dispatcher>
      </filter-mapping>
      <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ASYNC</dispatcher>
        <dispatcher>ERROR</dispatcher>
      </filter-mapping>
    ...
    

    with this Spring configuration

    
    ...
      <bean id="authenticationEntryPoint" class="test.AjaxAwareAuthenticationEntryPoint">
        <constructor-arg value="/pages/login.xhtml" />
      </bean>
      <security:http entry-point-ref="authenticationEntryPoint" use-expressions="true">
        <security:intercept-url pattern="/pages/login.xhtml" access="permitAll" />
        <security:intercept-url pattern="/javax.faces.resource/**" access="permitAll" />
        <security:intercept-url pattern="/**" access="isAuthenticated()" />
        <security:form-login login-page="/pages/login.xhtml" default-target-url="/pages/index.xhtml"
          always-use-default-target="false" />
      </security:http>
    ...
    

    Greets,
    Fabian

    • This topic was modified 1 year, 11 months ago by  fkoentopp.
    • This topic was modified 1 year, 11 months ago by  fkoentopp.
    #26381

    Hey,

    sorry for the delayed response.

    You could basically start with something like this:

    .addRule( Join.path( "/{tenant}/{url}" ).to( "/{url}" ).withChaining() )
    .where( "url" ).matches( ".*" )
    

    This way the tenant parameter will be converted into a query parameter which you can access using using the HttpServletRequest or via a view parameter.

    So basically you get:

    /oracle/somedir/somefile.jsf -> /somedir/somefile.jsf?tenant=oracle

    However, I’m unsure about Spring Security. You may need to do some tweaking here. But I’m not an expert for Spring Security. Just search the forums. There were some questions regarding Spring Security and AFAIK they were all answered.

    Good luck. 🙂

    #26387

    fkoentopp
    Participant

    Ok, thanks for the answer. My problem is indeed with Spring Security, where the incoming request is forwarded to the internal /pages/login.xhtml. When the request is filtered by the rewrite filter no tenant is available anymore. I want to have something like this:

    
    .addRule(Join.path("/{tenant}/{site}").to("/pages/{site}").withInboundCorrection())
    .when(Direction.isInbound())
    .where("tenant").constrainedBy(new Constraint<String>() {
    	@Override
    	public boolean isSatisfiedBy(Rewrite event, EvaluationContext context, String value) {
    		return !(value.contains("javax.faces") || value.contains("pages"));
    	}
    })
    
    .addRule(Join.path("/pages/{site}").to("/{tenant}/{site}"))
    .when(Direction.isOutbound())
    .where("tenant").configuredBy(new Converter<String>() {
    	@Override
    	public String convert(Rewrite event, EvaluationContext context, Object value) {
    		// Just an example
    		return "oracle";
    	}
    });
    

    How can I put something from outside (e.g. something stored as a session parameter) in the response? With that above I always get a ParameterizationException - "The value of required parameter [tenant] was null."

    • This reply was modified 1 year, 11 months ago by  fkoentopp.
    • This reply was modified 1 year, 11 months ago by  fkoentopp.
    #26395

    I think in your case it is not a very good idea to use Joins. A Join is basically a combination of an inbound and one outbound rule. So a join like this:

    .addRule( Join.path("/home") .to("/faces/home.xhtml") )
    

    Is basically the same as:

    .addRule()
    .when(Direction.isInbound().and(Path.matches("/home")))
    .perform(Forward.to("/faces/home.xhtml"))
    
    .addRule()
    .when(Direction.isOutbound().and(Path.matches("/faces/home.xhtml")))
    .perform(Substitute.with("/home"))
    

    Using these more fine grained rules, you have more control and I think you will be able to implement your requirement much more easily. You should give it a try. And just ask if you have any trouble.

    #26396

    BTW: The basic pattern for customizing the behavior of such a rule is to replace the operation with an anonymous class which may or may not delegate to some other options.

    So this rule:

    .addRule()
    .when(Direction.isOutbound().and(Path.matches("/faces/home.xhtml")))
    .perform(Substitute.with("/home"))
    

    Is the same as:

    .addRule()
    .when( Direction.isOutbound().and( Path.matches( "/faces/home.xhtml" ) ) )
    .perform( new HttpOperation() {
      @Override
      public void performHttp( HttpServletRewrite event, EvaluationContext context ) {
        Substitute.with( "/home" ).perform( event, context );
      }
    } )
    

    But it allows you to do stuff like:

    .addRule()
    .when( Direction.isOutbound().and( Path.matches( "/faces/home.xhtml" ) ) )
    .perform( new HttpOperation() {
      @Override
      public void performHttp( HttpServletRewrite event, EvaluationContext context ) {
    
        if(event.getRequest().getRemoteHost().contains( "microsoft.com" )) {
          Substitute.with( "/foo" ).perform( event, context );
        } else {
          Substitute.with( "/bar" ).perform( event, context );
        }
        
      }
    } )
    
    #26399

    fkoentopp
    Participant

    Ok, that helped a lot. Thanks for the support.

Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.

Comments are closed.