Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7504719
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 29, 20262026-05-29T21:39:52+00:00 2026-05-29T21:39:52+00:00

We are evaluating Shiro for a custom Saas app that we are building. Seems

  • 0

We are evaluating Shiro for a custom Saas app that we are building. Seems like a great framework does does 90% of what we want, out of the box. My understanding of Shiro is basic, and here is what I am trying to accomplish.

  • We have multiple clients, each with an identical database
  • All authorization (Roles/Permissions) will be configured by the clients
    within their own dedicated database
  • Each client will have a unique
    Virtual host eg. client1.mycompany.com, client2.mycompany.com etc

Scenario 1

Authentication done via LDAP (MS Active Directory)
Create unique users in LDAP, make app aware of LDAP users, and have client admins provision them into whatever roles..

Scenario 2

Authentication also done via JDBC Relam in their database

Questions:

Common to Sc 1 & 2 How can I tell Shiro which database to use? I
realize it has to be done via some sort of custom authentication
filter, but can someone guide me to the most logical way ? Plan to use
the virtual host url to tell shiro and mybatis which DB to use.

Do I create one realm per client?

Sc 1 (User names are unique across clients due to LDAP) If user jdoe
is shared by client1 and client2, and he is authenticated via client1
and tries to access a resource of client2, will Shiro permit or have
him login again?

Sc 2 (User names unique within database only) If both client 1 and
client 2 create a user called jdoe, then will Shiro be able to
distinguish between jdoe in Client 1 and jdoe in Client 2 ?

My Solution based on Les’s input..

public class MultiTenantAuthenticator extends ModularRealmAuthenticator {

    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        assertRealmsConfigured();
        TenantAuthenticationToken tat = null;
        Realm tenantRealm = null;

        if (!(authenticationToken instanceof TenantAuthenticationToken)) {
            throw new AuthenticationException("Unrecognized token , not a typeof TenantAuthenticationToken ");
        } else {
            tat = (TenantAuthenticationToken) authenticationToken;
            tenantRealm = lookupRealm(tat.getTenantId());
        }

        return doSingleRealmAuthentication(tenantRealm, tat);

    }

    protected Realm lookupRealm(String clientId) throws AuthenticationException {
        Collection<Realm> realms = getRealms();
        for (Realm realm : realms) {
            if (realm.getName().equalsIgnoreCase(clientId)) {
                return realm;
            }
        }
        throw new AuthenticationException("No realm configured for Client " + clientId);
    }
}

New Type of token..

public final class TenantAuthenticationToken extends UsernamePasswordToken {

       public enum TENANT_LIST {

            CLIENT1, CLIENT2, CLIENT3 
        }
        private String tenantId = null;

        public TenantAuthenticationToken(final String username, final char[] password, String tenantId) {
            setUsername(username);
            setPassword(password);
            setTenantId(tenantId);
        }

        public TenantAuthenticationToken(final String username, final String password, String tenantId) {
            setUsername(username);
            setPassword(password != null ? password.toCharArray() : null);
            setTenantId(tenantId);
        }

        public String getTenantId() {
            return tenantId;
        }

        public void setTenantId(String tenantId) {
            try {
                TENANT_LIST.valueOf(tenantId);
            } catch (IllegalArgumentException ae) {
                throw new UnknownTenantException("Tenant " + tenantId + " is not configured " + ae.getMessage());
            }
            this.tenantId = tenantId;
        }
    }

Modify my inherited JDBC Realm

public class TenantSaltedJdbcRealm extends JdbcRealm {

    public TenantSaltedJdbcRealm() {
        // Cant seem to set this via beanutils/shiro.ini
        this.saltStyle = SaltStyle.COLUMN;
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return super.supports(token) && (token instanceof TenantAuthenticationToken);
    }

And finally use the new token when logging in

// This value is set via an Intercepting Servlet Filter
String client = (String)request.getAttribute("TENANT_ID");

        if (!currentUser.isAuthenticated()) {
            TenantAuthenticationToken token = new TenantAuthenticationToken(user,pwd,client);
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  "
                        + "Please contact your administrator to unlock it.");
            } // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
                ae.printStackTrace();
            }
        }

}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-29T21:39:54+00:00Added an answer on May 29, 2026 at 9:39 pm

    You will probably need a ServletFilter that sits in front of all requests and resolves a tenantId pertaining to the request. You can store that resolved tenantId as a request attribute or a threadlocal so it is available anywhere for the duration of the request.

    The next step is to probably create a sub-interface of AuthenticationToken, e.g. TenantAuthenticationToken that has a method: getTenantId(), which is populated by your request attribute or threadlocal. (e.g. getTenantId() == ‘client1’ or ‘client2’, etc).

    Then, your Realm implementations can inspect the Token and in their supports(AuthenticationToken) implementation, and return true only if the token is a TenantAuthenticationToken instance and the Realm is communicating with the datastore for that particular tenant.

    This implies one realm per client database. Beware though – if you do this in a cluster, and any cluster node can perform an authentication request, every client node will need to be able to connect to every client database. The same would be true for authorization if authorization data (roles, groups, permissions, etc) is also partitioned across databases.

    Depending on your environment, this might not scale well depending on the number of clients – you’ll need to judge accordingly.

    As for JNDI resources, yes, you can reference them in Shiro INI via Shiro’s JndiObjectFactory:

    [main]
    datasource = org.apache.shiro.jndi.JndiObjectFactory
    datasource.resourceName = jdbc/mydatasource
    # if the JNDI name is prefixed with java:comp/env (like a Java EE environment),
    # uncomment this line:
    #datasource.resourceRef = true
    
    jdbcRealm = com.foo.my.JdbcRealm
    jdbcRealm.datasource = $datasource
    

    The factory will look up the datasource and make it available to other beans as if it were declared in the INI directly.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Am evaluating 960 gs css framework for using on my site. Does anyone knows
I'm evaluating and looking at using CherryPy for a project that's basically a JavaScript
We are currently evaluating different applications that interface with Visual Studio 2008 (C#) and
I'm currently evaluating CodeRush and one thing that I liked most when reading the
Evaluating Tinymce. I've looked at the docs/source/api, and have a question that I thought
When evaluating if(-t STDIN) , does the < UNIX operator count as STDIN? If
I'm evaluating Hibernate Shards for a project that uses hibernate-jpa. I was wondering how
I am evaluating an algorithm, and would like to use artificial data. The algorithm
Currently evaluating Dreamweaver CS 5.5. I like much of it - but wondering about
While evaluating Visual Studio 2010 Beta 2, I see that in the converted directory,

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.