Announcement Announcement Module
Collapse
No announcement yet.
What if I have to collect authorization data after authent? Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • What if I have to collect authorization data after authent?

    I already use FilterInvocationInterceptor but would like to collect extra information from an authenticated user before poroceeding the authorization. What's the best approach?

    Thanks
    Mauricio

  • #2
    What extra information would you like to collect? Require an additional property in order to authenticate?

    Here are a few threads that provide possibly useful background info:

    http://forum.springframework.org/showthread.php?t=12422

    http://forum.springframework.org/showthread.php?t=10773

    http://forum.springframework.org/showthread.php?t=10428
    Last edited by robyn; May 19th, 2006, 06:58 AM.

    Comment


    • #3
      What if I have to collect authorization data after authent?

      Thanks for your attention Ben.

      To be more specific, I want to grant or deny access to an already authenticated user based upon a choice.

      Example:

      1. User is authenticated (let's say he/she is now level 1).
      2. Read the contracts where he/she is enlisted from the db; a user may have some privileges within a contract but may not have the same privileges within another .
      3. Present a page where the user can choose from the list of contracts.
      4. Keep the choosen contract in UserDetails and update the Authentication object to reflect the correct privileges in getAuthorities(), using a custom DaoAuthenticationProvider, like in topic 899 (user is now level2).

      This is different from the other topics in the forum because I would like to get information from the user between authentication and authorization.

      Of course, I can authenticate the user myself, without using acegi security, at step 1. I feel this is not the best practice since it will be authenticated again by acegi at a next step.

      After some unsuccessfull attempts to turn such a workflow into acceptable code, I am now considering an alternative approach: I will not ask the user to choose a contract in step 3, instead, I will make a first choice, either a default or a previous choice. From that stage on, the contract option can be changed at the user's will, and all that I have to do is to update the Authentication to reflect the correct authorities.

      Well then, to clarify my questions:

      a) Is the first workflow feasible? Does it have anything to do with the after invocation feature from the 0.7.0 release? Or RunAsManager? Do I have to write a custom Voter?

      b) If I follow the second approach, how do I "safely" update the Authentication object to reflect a change of contract , and as a consequence, authorities?

      Thank you again for your kindness to reply. I should also say that I consider both your job and your promptness to help, along with the spring framework team, as a reference for top quality development. Congratulations.

      Maurício Castro

      Comment


      • #4
        It would be my first instinct you're trying to use Authentication for more than it was intended to be used for. Whilst you could construct an MVC controller that will do everything you listed, would it not be easier to simply use the ACL capabilities of Acegi Security? By doing that the user would login, and their Authentication would not change. Instead at the time of accessing the contract, the user's relevant permissions to the contract domain object will be retrieved and security enforced.

        If you need a notion of a user "acting on behalf" of a particular user, so they can only do one thing at a time, your alternative is to extend SecureContextImpl with your own context that will store the present "acting-on-behalf-contract-id". Thus you still would leave ACL management to Acegi Security, and you wouldn't be modifying the Authentication object, but you'd be storing in a convenient ThreadLocal which contract they're acting on behalf of. Andreas Schildbach did something similar with locale management, so you might like to search for posts on the forum and Acegi Security deveopers list if you need a ContextHolder modification approach.

        Comment


        • #5
          What if I have to collect authorization data after authent?

          Thanks, Ben. Surely I didn' t give the ACL capability of Acegi the proper attention. Indeed, I was able to get things working using a similar approach to the Context modification: I wrote an adapter to the user retrieved by Authentication.getPrincipal() to store the contract id in connection with a Custom AuthenticationDao. The code is below.
          Code:
          //Created on 05/02/2005
          package com.iservport.acegisecurity;
          
          import java.util.ArrayList;
          import java.util.Iterator;
          import java.util.List;
          import java.util.Set;
          
          import com.iservport.admin.Authority;
          import com.iservport.admin.Role;
          import com.iservport.admin.User;
          import com.iservport.admin.dao.ContractDao;
          import com.iservport.admin.dao.ModeratorDao;
          
          import net.sf.acegisecurity.GrantedAuthority;
          import net.sf.acegisecurity.GrantedAuthorityImpl;
          import net.sf.acegisecurity.UserDetails;
          
          /**
           * @author <a href="[email protected]">Maurício Fernandes de Castro</a>
           */
          public class PrincipalImpl implements UserDetails &#123;
              
              protected User user;
              
              public PrincipalImpl&#40;User user&#41; &#123;
                  this.user = user;
              &#125;
              
              /**
               * @return Returns the user.
               */
              public User getUser&#40;&#41; &#123;
                  return user;
              &#125;
              /**
               * @param user The user to set.
               */
              public void setUser&#40;User user&#41; &#123;
                  this.user = user;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#getAuthorities&#40;&#41;
               */
              public GrantedAuthority&#91;&#93; getAuthorities&#40;&#41; &#123;
                  Set authorities = user.getAuthorities&#40;&#41;;
                  List list = new ArrayList&#40;&#41;;
                  for &#40;Iterator it = authorities.iterator&#40;&#41;; it.hasNext&#40;&#41;;&#41; &#123;
                      Role role = &#40;&#40;Authority&#41; it.next&#40;&#41;&#41;.getRole&#40;&#41;;
                      String roleToAuthority = "ROLE_"+role.getService&#40;&#41;.getServiceName&#40;&#41;+"_"+role.getRoleName&#40;&#41;;
                      list.add&#40;new GrantedAuthorityImpl&#40;roleToAuthority&#41;&#41;;
                  &#125;
                  return &#40;GrantedAuthority&#91;&#93;&#41; list.toArray&#40;new GrantedAuthority&#91;authorities.size&#40;&#41;&#93;&#41;;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#getPassword&#40;&#41;
               */
              public String getPassword&#40;&#41; &#123;
                  return this.user.getCredential&#40;&#41;.getPassword&#40;&#41;;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#getUsername&#40;&#41;
               */
              public String getUsername&#40;&#41; &#123;
                  return this.user.getCredential&#40;&#41;.getEmail&#40;&#41;;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#isAccountNonExpired&#40;&#41;
               */
              public boolean isAccountNonExpired&#40;&#41; &#123;
                  return &#40;this.user.getContract&#40;&#41;.getStatus&#40;&#41;==ContractDao.ACTIVE_CONTRACT&#41;;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#isCredentialsNonExpired&#40;&#41;
               */
              public boolean isCredentialsNonExpired&#40;&#41; &#123;
                  return true;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see net.sf.acegisecurity.UserDetails#isEnabled&#40;&#41;
               */
              public boolean isEnabled&#40;&#41; &#123;
                  return &#40;this.getUser&#40;&#41;.getCredential&#40;&#41;.getState&#40;&#41;==ModeratorDao.STATE_CONFIRMED&#41;;
              &#125;
          &#125;
          So, when I need the Contract id, it is aggregated into User as user.getContract(). Here is the AuthenticationDao (ServiceAuthenticationDao is a super interface):

          Code:
          //Created on 05/02/2005
          package com.iservport.acegisecurity;
          
          import java.util.List;
          
          import org.springframework.dao.DataAccessException;
          import org.springframework.orm.hibernate.support.HibernateDaoSupport;
          
          import com.iservport.admin.Credential;
          import com.iservport.admin.Region;
          import com.iservport.admin.User;
          
          import net.sf.acegisecurity.UserDetails;
          import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
          
          /**
           * @author <a href="[email protected]">Maurício Fernandes de Castro </a>
           */
          public class AuthenticationDaoImpl extends HibernateDaoSupport implements
                  ServiceAuthenticationDao &#123;
          
              private String regionName = "default";
          
              private String serviceName = "research";
          
              /* &#40;non-Javadoc&#41;
               * @see com.iservport.acegisecurity.ServiceAuthenticationDao#getRegionName&#40;&#41;
               */
              public String getRegionName&#40;&#41; &#123;
                  return regionName;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see com.iservport.acegisecurity.ServiceAuthenticationDao#setRegionName&#40;java.lang.String&#41;
               */
              public void setRegionName&#40;String regionName&#41; &#123;
                  this.regionName = regionName;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see com.iservport.acegisecurity.ServiceAuthenticationDao#getServiceName&#40;&#41;
               */
              public String getServiceName&#40;&#41; &#123;
                  return serviceName;
              &#125;
              /* &#40;non-Javadoc&#41;
               * @see com.iservport.acegisecurity.ServiceAuthenticationDao#setServiceName&#40;java.lang.String&#41;
               */
              public void setServiceName&#40;String serviceName&#41; &#123;
                  this.serviceName = serviceName;
              &#125;
              /*
               * &#40;non-Javadoc&#41;
               * 
               * @see net.sf.acegisecurity.providers.dao.AuthenticationDao#loadUserByUsername&#40;java.lang.String&#41;
               */
              public UserDetails loadUserByUsername&#40;String username&#41;
                      throws UsernameNotFoundException, DataAccessException &#123;
                  // TODO enforce uniqueness in AuthenticationDaoImpl
                  Credential credential = &#40;Credential&#41; this.getHibernateTemplate&#40;&#41;.find&#40;
                          "from Credential where email = ?", username&#41;.get&#40;0&#41;;
                  if &#40;credential == null&#41; &#123;
                      throw new UsernameNotFoundException&#40;"User not found!"&#41;;
                  &#125;
                  Region region = &#40;Region&#41; this.getHibernateTemplate&#40;&#41;.find&#40;
                          "from Region where uniqueRegion = ?", regionName&#41;.get&#40;0&#41;;
                  // TODO instead of first user contract, take preferred contract in AuthenticationDaoImpl
                  Object&#91;&#93; args = new Object&#91;3&#93;;
                  args&#91;0&#93; = credential.getId&#40;&#41;;
                  args&#91;1&#93; = region.getLocale&#40;&#41;;
                  args&#91;2&#93; = serviceName;
                  List users = this.getHibernateTemplate&#40;&#41;.find&#40;
                          "from User user where " + "user.credential.id = ? and "
                                  + "user.contract.service.locale = ? and "
                                  + "user.contract.service.serviceName = ?", args&#41;;
                  if &#40;users != null && users.size&#40;&#41;>0&#41; &#123;
                      PrincipalImpl principal = new PrincipalImpl&#40;&#40;User&#41; users.get&#40;0&#41;&#41;;
                      return principal;
                  &#125;
                  throw new UsernameNotFoundException&#40;"User not authorized!"&#41;;
              &#125;
          &#125;
          And that is it!

          Thanks for the help.

          Comment

          Working...
          X