Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Domain style logins (not NT domains!)

  1. #1
    Join Date
    Aug 2004
    Posts
    27

    Default Domain style logins (not NT domains!)

    I need to support domain based logins.

    To me, a domain is a collection of unique users, each having a unique username.

    Therefore it is possible to have two users in the system with the same username, with a different domain.

    I have a custom, simple, security system that implements this via a domain property on the user object. I want to migrate to acegi. I am wondering if I should just prefix the username with the domain name, separated by a delimiter. Or if a domain property could be introduced into acegi ?

    I guess the issue is, would this sort of use case be a good thing to integrate into acegi core ?

    Thanks,

    Cameron

  2. #2
    Join Date
    Aug 2004
    Location
    Sydney, Australia
    Posts
    2,768

    Default

    I would encourage the prefix approach, because most authentication infrastructure is geared to work with a single username and single password. By using a prefix you can tie into that existing infrastructure, such as BASIC authentication and CAS authentication.

    A prefix is easy enough to work with. Your AuthenticationDao would be the place to tokenize the presented username, assuming you want a separate database column for the domain. Your DaoAuthenticationProvider could optionally be subclassed and the createSuccessAuthentication overridden to return a new Authentication object which has a convenience getter for the domain. If using form-based authentication you'd need to override the AuthenticationProcessingFilter to prepend the domain and delimiter.

    I'm happy to add any contributions which make it easier to do something like the above.

  3. #3
    Join Date
    Aug 2004
    Posts
    27

    Default

    thanks for your informative and prompt response.

    I think your approach will work very well.


    I'll let you know how it goes.

    Thanks agin.

  4. #4
    Join Date
    Jun 2005
    Location
    Mississauga, ON
    Posts
    6

    Default

    Now a days, more and more Applications need manage multi - domain, the username will be not unique. I think it is not good to use a prefix approach. We need a new Authentication implementation which has a "domain" property, and change the
    Code:
    public UserDetails loadUserByUsername(String username)
    of AuthenticationDao to
    Code:
    public UserDetails loadUserByUsername(Authentication authentication )
    or add
    Code:
    public UserDetails loadUserByUsername(Authentication authentication )
    into AuthenticationDao

    and same with the
    Code:
    private UserDetails getUserFromBackend(String username)
    of DaoAuthenticationProvider

  5. #5
    Join Date
    Aug 2004
    Location
    Sydney, Australia
    Posts
    2,768

    Default

    Your proposal is already in effect offered by the AuthenticationProvider and AuthenticationManager interfaces. If you had more complex needs than could be addressed via a prefix approach, you'd simply implement either of these interfaces (typically AuthenticationProvider, so it can still be used in a chained configuration and swapped easily with other AuthenticationProviders).

  6. #6
    Join Date
    Jun 2005
    Location
    TX
    Posts
    3

    Default

    We are working on project that has multiple administrative domains. Our planned approach is to decorate AuthenticationProviders with a regular expression based domain matcher. Users use an email style username. We plan to use the information in the username to determine which AuthenticationProvider should be used. Then we map the username to the format required by the underlying AuthenticationProvider (and user store).

    I believe this approach should work with DaoAuthenticationProvider.

    Questions:
    1. Are we making a new wheel or is similar functionality already part of Acegi? Without additional code?

    2. Does this seem like a reasonable approach to the Acegi experts?

    Feedback is appreciated.

    The Spring context will look something like this:

    Code:
    <bean id="department1AuthenticationProvider"
    	class="RegexMatchingProvider" />
         <constructor-arg>
              <ref local=" department1DaoAuthenticationProvider"/>
         </constructor-arg>
         <property name="domainRegex">
              <value>\w+@department1.company.com</value>
         </property>
         <property name="usernameRegex">
              <value>&#40;\w+&#41;@department1.company.com</value>
         </property>
         <property name="usernameReplacement">
              <value>$1</value>
         </property>
    </bean>
    
    <bean id="department2AuthenticationProvider"
    	class="RegexMatchingProvider" />
         <constructor-arg>
              <ref local=" department2DaoAuthenticationProvider"/>
         </constructor-arg>
         <property name="domainRegex">
              <value>department2\\\w+</value>
         </property>
    </bean>
    
    <bean id="authenticationManager"
    	class="net.sf.acegisecurity.providers.ProviderManager">
         <property name="providers">
              <list>
                   <ref local="department1AuthenticationProvider" />
                   <ref local="department2AuthenticationProvider" />
              </list>
         </property>
    </bean>

    Code:
    /**
     * An <code>AuthenticationProvider</code> decorator used to support multiple
     * administrative domains.
     * 
     * This decorator only works with <code>AuthenticationProvider</code>s that
     * support <code>UsernamePasswordAuthenticationToken</code> using either a
     * <code>String</code> or <code>User</code> as the Principal.
     * 
     * A JDK regular expression is used to determine if a username provided in the
     * Principal is in an administrative domain. If the username is
     * <code>null</code> or does not match the regular expression,
     * <code>authenticate&#40;&#41;</code> returns null indicating this
     * <code>AuthenticationProvider</code> does not support authentication for
     * this domain. If the username matched the regular expression it may be
     * modified before being delegated to the underlying
     * <code>AuthenticationProvider</code>. See
     * <code>setUsernameRegex&#40;&#41;</code> for further information. The
     * original username is replaced before the <code>Authentication</code> is
     * returned.
     * 
     * For example, <code>user1@department1.company.com</code> can be mapped to
     * <code>user1</code> then authenticated against depatment1’s user store.
     * Another AuthenticationProvider can be decorated to only authenticate
     * usernames in the form <code>department2\\user</code> against department2’s
     * user store.
     * 
     */
    
    public class RegexMatchingProvider implements AuthenticationProvider &#123;
    
    // impl removed
    
    	public RegexMatchingProvider&#40;AuthenticationProvider authenticationProvider&#41; &#123;
    // impl removed
    	&#125;
    
    
    	public Authentication authenticate&#40;Authentication authentication&#41;
    			throws AuthenticationException &#123;
    // impl removed
    &#125;
    
    
    
    	/**
    	 * 
    	 * The expression used to determine if this AuthenticationProvider should be
    	 * used for authentication.
    	 * 
    	 * @param domainRegex
    	 *            The JDK regular expression to use to determine if this
    	 *            AuthenticationProvider should be used for authentication.
    	 */
    	public void setDomainRegex&#40;String domainRegex&#41; &#123;
    // impl removed
    	&#125;
    
    	/**
    	 * 
    	 * The expression provided here is used in the matching part of the
    	 * substitution operation. Think Perl 5&#58;
    	 * s/$usernameRegex/$usernameReplacement/g
    	 * 
    	 * See replaceAll&#40;&#41; in java.util.regex.Matcher for further information.
    	 * 
    	 * @param usernameRegex
    	 *            The JDK regular expression used to extract the domain specific
    	 *            username from the username provided.
    	 *  
    	 */
    	public void setUsernameRegex&#40;String usernameRegex&#41; &#123;
    // impl removed
    	&#125;
    
    	/**
    	 * 
    	 * The expression provided here is used as the substitution string in the
    	 * substitution operation. Think Perl 5&#58;
    	 * s/$usernameRegex/$usernameReplacement/g
    	 * 
    	 * See replaceAll&#40;&#41; in java.util.regex.Matcher for further information.
    	 * 
    	 * @param usernameReplacement
    	 *            The username will be replaced according to the expression
    	 *            provided. Dollar signs may be treated as references to
    	 *            captured subsequences.
    	 *  
    	 */
    	public void setUsernameReplacement&#40;String usernameReplacement&#41; &#123;
    // impl removed
    	&#125;
    
    &#125;

  7. #7
    Join Date
    Aug 2004
    Location
    Sydney, Australia
    Posts
    2,768

    Default

    It looks a reasonable approach, although I would consider moving the logic to the AuthenticationDao instead of the AuthenticationProvider, and possibly using a PropertyEditor so that you can have, for example:

    Code:
    <bean id="departmentAwareAuthenticationDao" class="AuthDao">
      <property name="dataSource"><ref local="dataSource"/></property>
      <property name="departments">
        <value>
          \w+@department1.company.com=&#40;\w+&#41;@department1.company.com,$1
          \w+@department2.company.com=&#40;\w+&#41;@department2.company.com,$1
        </value>
      </property>
    </bean>

  8. #8
    Join Date
    Mar 2007
    Posts
    3

    Default Still the case?

    Hi,

    I was wondering, almost 2 years later, if the prefix approach is still the way to go or if there is some better approach to authenticate a user using more than the usual username/password pair.

    In my case, the username is unique in the system, but the roles associated to the user depend on the third parameter (the domain). So I need to get the user info from the DB with this in mind, but once I have the user with the authorities related to the supplied domain, the rest of the authentication is the same.

    I see 2 interesting ways to do that :

    1. Don't prefix the username with the domain.

    1.1. Subclass AuthenticationProcessingFilter (override attemptAuthentication(...)) and UsernamePasswordAuthenticationToken to take care of and add the third property (domain).
    1.2. Subclass DaoAuthenticationProvider and override retrieveUser(...) to call UserDetailsService.loadUserByAuthentication(authen tication) instead of loadUserByUsername(username).
    1.3. Subclass JdbcDaoImpl (my UserDetailsService) and add loadUserByAuthentication(Authentication) and take care of the domain in the authoritiesByUsernameQuery.

    2. Prefix the username with the domain.

    2.1. Subclass AuthenticationProcessingFilter to forge the concatenated username for UsernamePasswordAuthenticationToken.
    2.2. Subclass JdbcDaoImpl (my UserDetailsService) to unforge the domain from the username, get the user with that.
    2.3. I wonder if I have to put back the real unconcatenated username in the Authentication for future use in the application?? If it is put in the SecurityContextHolder with the prefix, then I will have to unforge the username each time I want to use it in the application? If I put the unforged username in it, and I don't have any caching, will it try to authenticate later without the prefix and won't be able to?

    Does that make sense? Do you have any more advice?

    Thanks in advance.

  9. #9
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,425

    Default

    IMHO, I think the prefix is still the easier way to go. It should be pretty quick and straight forward to implement.

  10. #10
    Join Date
    Mar 2007
    Posts
    3

    Default returnUsername

    Thanks karldmoore for your advice.

    I decided to go with the concatenated way. Now I have a question.

    If for instance John's username is "john" with domain_id "1", the UsernamePasswordAuthenticationToken's username field will be "1:john". But we know that in the DB, the username is "john". So, in the UserDetailsService.loadUserByUsername(String username) method, the loaded username will be "john". At the end of the method, we have:


    String returnUsername = user.getUsername(); // this is "john"

    if (!isUsernameBasedPrimaryKey()) {
    returnUsername = username; // this is "1:john" or whatever...
    }

    return new User(returnUsername, user.getPassword(), user.isEnabled(), true, true, true, arrayAuths);


    So the database username of "john" will be put back in the Authentication object (via the principal -- User).

    Now the question : is the Authentication object, stored in the SecurityContext, used later, after the login, by Acegi for authentication purposes -- for example, if I don't have caching, will it go through the whole authentication process again?

    If so, we all know it won't work because "john" will be used instead of "1:john".

    Actually, I was wondering why there is the "returnUsername" thing at the end of the method.

    What are your thoughts? Thanks for reading.

Similar Threads

  1. Avoiding UI-centric Domain Classes
    By dhainlin in forum Web
    Replies: 5
    Last Post: Mar 27th, 2006, 01:16 PM
  2. Replies: 2
    Last Post: Oct 10th, 2005, 05:12 PM
  3. Loosing my SecureContext
    By sklakken in forum Security
    Replies: 3
    Last Post: Jul 21st, 2005, 01:44 PM
  4. EJB service layer non-OO / Anemic Domain Model
    By Aro in forum Architecture
    Replies: 0
    Last Post: Jan 15th, 2005, 07:10 AM
  5. Replies: 0
    Last Post: Jan 6th, 2005, 08:19 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •