Quantcast

Add principals to AuthenticationInfo object after doGetAuthenticationInfo returns

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Add principals to AuthenticationInfo object after doGetAuthenticationInfo returns

mahony576
I have a use case where my own site (A) consolidates data from other sites.  When a user logs into site A, those credentials are used to login to the other sites.  A user might have access to all or none of the other sites.  

I launch threads to login to the other sites.  When I wait on all the threads to complete, everything works as expected.  To speed up the login, I want the login to return when the first successful login completes.  However, when I do this, there seems to be a race condition where not all of the successful principals are added.  Sometimes I get access to all the sites, sometimes only a partial list.

The real question is can principals be added to the AuthenticationInfo object after it is returned from doGetAuthenticationInfo()?

This is my doGetAuthenticationInfo code in my realm:

        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                        AuthenticationToken token) throws AuthenticationException {
               
                List<String> urls = getUrls();
                UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
                MyAuthenticationInfo authInfo = new MyAuthenticationInfo(token.getCredentials(),
                                                                                                                                        this.getName());
               
                ArrayList<LoginTask> threads = new ArrayList<LoginTask>();
                for (String url: urls) {
                        LoginTask t = new LoginTask(url, usernamePasswordToken, authInfo);
                        t.start();
                        threads.add(t);
                }

                boolean successful = false;
                int threadsComplete = 0;
                while (!successful && threadsComplete < threads.size() - 1) {
                        threadsComplete = 0;
                        for (LoginTask t : threads) {
                                if (!t.isAlive()) {
                                        threadsComplete++;
                                        if (t.getPrincipal() != null) {
                                                successful = true;
                                                break;
                                        }
                                }
                                try {
                                        Thread.sleep(100);
                                } catch (InterruptedException e) {
                                }
                        }
                }
   
                return authInfo;
        }

The login thread calls this:

        public void run() {
                try {
                        String username = m_usernamePasswordToken.getUsername();
                        String password = new String(m_usernamePasswordToken.getPassword());
                        Subject s = SecurityUtils.getSubject();
                        String sessionId = s.getSession().getId().toString();
                        doLogin(m_url, username, password, sessionId);  //throws exception if login fails
                       
                        m_principal = new MyPrincipal(m_usernamePasswordToken.getPrincipal().toString(), sessionId, m_url.toLowerCase());
                        m_authInfo.addPrincipal(m_principal);
                } catch (Exception e) {
                } finally {
                        ThreadContext.unbindSubject();
                        ThreadContext.remove();
                }
        }

I'm guessing the problem is once the main thread in doGetAuthenticationInfo() is returned, I can't add more principals to that AuthenticationInfo object.  But why?  Is there a way around this?


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Add principals to AuthenticationInfo object after doGetAuthenticationInfo returns

mahony576
I think I found a fix, where instead of adding the principal directly to the authentication info object:

                        m_principal = new MyPrincipal(m_usernamePasswordToken.getPrincipal().toString(), sessionId, m_url.toLowerCase());
                        m_authInfo.addPrincipal(m_principal);

If I get the principal collection from the subject, and add it that way, it seems to work:

                        m_principal = new SvtPrincipal(m_usernamePasswordToken.getPrincipal().toString(), sessionId, m_lamsUrl.toLowerCase());
                        SvtPrincipalCollection p = (SvtPrincipalCollection)SecurityUtils.getSubject().getPrincipals();
                        if (p == null) {
                                m_authInfo.addPrincipal(m_principal);
                        } else {
                                p.add(m_principal, "lamsRealm");
                        }


I would still appreciate a response to let me know if this approach is valid.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Add principals to AuthenticationInfo object after doGetAuthenticationInfo returns

Brian Demers
In reply to this post by mahony576
Depending on how you have things configured, Shiro will merge an AuthenticationInfo from each realm you have configured.

If you do work around your current issue, I think you are going to run into other inconsistency issues.

Using a webapp as example, say you make a request using basic auth, and this request requires permissions from your 3rd source (one that takes the longest).  If you return from the 'doGetAuthenticationInfo()' (or calling methods) before waiting for the 3rd source. The request would fail (with a 403).  But if you repeated that same request again (assuming the results were cached, the result would be successful)

On Tue, Nov 22, 2016 at 2:56 PM, mahony576 <[hidden email]> wrote:
I have a use case where my own site (A) consolidates data from other sites.
When a user logs into site A, those credentials are used to login to the
other sites.  A user might have access to all or none of the other sites.

I launch threads to login to the other sites.  When I wait on all the
threads to complete, everything works as expected.  To speed up the login, I
want the login to return when the first successful login completes.
However, when I do this, there seems to be a race condition where not all of
the successful principals are added.  Sometimes I get access to all the
sites, sometimes only a partial list.

*The real question is can principals be added to the AuthenticationInfo
object after it is returned from doGetAuthenticationInfo()?*

This is my doGetAuthenticationInfo code in my realm:

        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                        AuthenticationToken token) throws AuthenticationException {

                List<String> urls = getUrls();
                UsernamePasswordToken usernamePasswordToken =
(UsernamePasswordToken)token;
                MyAuthenticationInfo authInfo = new
MyAuthenticationInfo(token.getCredentials(),
                                                                                                                                        this.getName());

                ArrayList<LoginTask> threads = new ArrayList<LoginTask>();
                for (String url: urls) {
                        LoginTask t = new LoginTask(url, usernamePasswordToken, authInfo);
                        t.start();
                        threads.add(t);
                }

                boolean successful = false;
                int threadsComplete = 0;
                while (!successful && threadsComplete < threads.size() - 1) {
                        threadsComplete = 0;
                        for (LoginTask t : threads) {
                                if (!t.isAlive()) {
                                        threadsComplete++;
                                        if (t.getPrincipal() != null) {
                                                successful = true;
                                                break;
                                        }
                                }
                                try {
                                        Thread.sleep(100);
                                } catch (InterruptedException e) {
                                }
                        }
                }

                return authInfo;
        }

The login thread calls this:

        public void run() {
                try {
                        String username = m_usernamePasswordToken.getUsername();
                        String password = new String(m_usernamePasswordToken.getPassword());
                        Subject s = SecurityUtils.getSubject();
                        String sessionId = s.getSession().getId().toString();
                        doLogin(m_url, username, password, sessionId);  //throws exception if
login fails

                        m_principal = new
MyPrincipal(m_usernamePasswordToken.getPrincipal().toString(), sessionId,
m_url.toLowerCase());
                        m_authInfo.addPrincipal(m_principal);
                } catch (Exception e) {
                } finally {
                        ThreadContext.unbindSubject();
                        ThreadContext.remove();
                }
        }

I'm guessing the problem is once the main thread in
doGetAuthenticationInfo() is returned, I can't add more principals to that
AuthenticationInfo object.  But why?  Is there a way around this?






--
View this message in context: http://shiro-user.582556.n2.nabble.com/Add-principals-to-AuthenticationInfo-object-after-doGetAuthenticationInfo-returns-tp7581395.html
Sent from the Shiro User mailing list archive at Nabble.com.

Loading...