Announcement Announcement Module
Collapse
No announcement yet.
Acegi and SiteMinder Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Acegi and SiteMinder

    I'm trying to determine if Acegi would be useful to us given our security environment. We use SiteMinder to handle all of our authentication requirements. Since SiteMinder runs as an Apache module, the user has already been authenticated by the time he or she would hit our application. In the past we would simply retrieve the user's username out of the request header with request.getHeader("sm_user") and then look up the user's details from the database to determine the user's capabilities within the application.

    In an effort to centralize the user/group/role functionality required by virtually every one of our applications, we are in the process of developing a centralized "user management" application. This application will store all user data, the various applications to which the user has access, and the rights a user has within a particular application. An application in need of user management services would make a TBD remote call to the user management app to look up the user details and authorities.

    Since our authentication needs are already handled by SiteMinder, is it still practical for us to look to Acegi to help with our authorization needs? I'm impressed by Acegi's architecure and capabilities, but I'm not quite clear how we would approach using it in our environment. Based on some earlier posts on this board (http://forum.springframework.org/vie...ght=siteminder) it appears that we would begin by creating a custom implementation of the HttpSessionContextIntegrationFilter to populate the ContextHolder with a Context object containing the sm_user header wrapped in an Authentication object. Does this sound correct so far? Are there other custom classes we would need to write given our environment? Is the fact that we'll be issuing remote calls to our user management application complicate matters?

    I would appreciate any advice on this topic.

    Thanks,
    Bob

  • #2
    The way I'd approach your use case is to write an authentication processing filter similar to DigestProcessingFilter or BasicProcessingFilter. It will essentially know the user was authenticated based on the presence of the HttpServletRequest.getHeader("sm_user"). It will then put that username into the ContextHolder, along with an application-specific private key. You do not need to write any custom ContextHolder or ContextHolder interaction class. You'd then use DaoAuthenticationProvider as normal, writing a custom AuthenticationDao. The custom AuthenticationDao would do your web services query to obtain the relevant roles and build a UserDetails object. The password in the UserDetails would be your application-specific private key. That would be all that's required for your solution to work. The inbuilt caching offered by UserCache would minimise unnecessary web services call.

    Comment


    • #3
      Acegi and SiteMinder

      Just to share info:

      I have an analogous configuration. Here is how we manage it:
      • (1) The user authenticates to SiteMinder. His account is stored in LDAP. Upon successfully authentication, SiteMinder redirects the user to the requested web app.
      • (3) The web app has another filter that retrieves the user id (via SM_USER) and then automatically logs in to Acegi with an arbitrary password.
      Configuration of Acegi:
      • We use the standard DaoAuthenticationProvider
      • with a custom implementation of AuthenticationDao which does 2 things: (1) this dao accepts any user id: it creates a User and associates it with the above arbitrary password, ensuring the password checking by Acegi is successful; (2) this dao also reads the groups of the user from LDAP; the mapping between groups and roles is defined in the configuration file
      (No problem to share further experience and/or source code)
      Hope this help.
      Cheers,

      -- Savrak

      Comment


      • #4
        Here's my solution with Siteminder - let me know if you want finer details:

        I extended Acegi 0.8.1's AuthenticationProcessingFilter to allow for the definition of Siteminder username and password header keys as well as form property keys using the filter's Spring context config. The filter extension then tries to get the username and password from the Siteminder headers, and if it doesn't see any, it tries to find them using the form properties. This makes it easy to move from development, where Siteminder isn't installed, to UAT and Production without omitting security anywhere. It also provides for extra protection in case a server admin removes the Siteminder ISAPI filter by mistake...

        Subsequent processing of the username and password seems redundant, since Siteminder has already done it in UAT and Prod, but our AuthenticationDAO (it's actually a transaction-wrapped Service by the way, since we reference two data sources) doesn't care - it already has that info available anyway. As in Savrak's solution, you could also use an arbitrary password, but it wouldn't give you any real security in the DEV environment or when Siteminder is disabled. Likewise, I'd be happy to share my source and context files.

        Scott

        Comment


        • #5
          Scott, Savrak:

          If the offer is still on the table, I'd love to see your code.

          I'm new to Acegi and moderately experienced with Spring. I'm reading the Acegi guide now, and looking at the sample apps, and checking out this forum.

          I'm looking for a way to use Acegi, and make the web application as independent as possible from whatever is used for authentication and authorization (roles). The web app can be deployed into an enterprise environment, and the customer may be happy using container managed security, or perhaps they are using an SSO product such as Netegrity, RSA, Cafesoft etc., or some homebrew solution.

          I need some ways to partition things, so I can plug in (i.e. most likey write) 'environment specific' stuff as needed. I realize this won't all come for free just by using Acegi. That's okay, but I don't want to have to make changes to the main webapp each time. Simply changing the application context and adding the required custom classes to the classpath would be great.

          To make this more 'interesting', this application is in transition. It is partly Spring enabled (services via HttpInvoker), and the rest straight servlet and JSPs. In addition, it will be running with its existing JRun 3.1 app server, which does not support servlet filters. It seems filters are a significant hook for Acegi security.

          We have our own authentication implementation so that JRun can do container managed security, which works well enough. The FORM based login, and establishment of the session occurs as you'd expect. This would be the first form of authentication to plug into Acegi. Before too long, we will need to move to a more modern app server, especially since no SSO vendor really supports JRun 3.x.

          Given no servlet filter, I will need to create some choke-points in the existing servlets and JSPs (this app is not a good example of MVC). I think for the new HttpInvoker stuff, I could just define a handler interceptor, or perhaps even extend DispatcherServlet. In all cases, the choke point needs to set up what Acegi needs to work properly downstream, which will entail some finer grained ACL/permissions.

          I will continue reading and look at the existing Acegi filter source to get some clues.

          Thank you for any pointers,

          Jeff

          Comment


          • #6
            Jeff, the stock Acegi docs and examples will probably help you more than my code for just getting started, but if you get to the point where you have Acegi implemented and want to tie it to Siteminder, let me know and I'll send you my filter extension. Good luck!

            Scott

            Comment


            • #7
              SiteMinder can return user roles through HTTP header similar to SM_USER for authenticated user ID as well, right? Could you help to explain your use case:

              Q: why do you just want SM to authenticate but leave authorization to apps instead of letting SM do the az part?

              I am designing an app that needs to support both my embedded auth and az, and also third party policy servers such as SiteMinder / IBM TAM. I am thinking to adopt ACEGI to my embedded az, and hope to easily turn off my default one when third party az system is used. I don't like to ship two versions web.xml that would include "security-constraint" to kick off role based access. Do you think that ACEGI is good for this?

              Thanks

              - Ming

              Comment


              • #8
                Originally posted by mpei
                Q: why do you just want SM to authenticate but leave authorization to apps instead of letting SM do the az part?
                It's because Siteminder doesn't have the role/group information I need for my application. The permissions that users have are closely coupled with our back-end host data, and thus cannot be expressed using SM/LDAP groups or entry attributes.

                If on the other hand you are able to express permissions using SM attributes, then go for it!

                Scott

                Comment


                • #9
                  For the benefit of the forum archives, I've added a JIRA issue to do with tighter connector integration: http://opensource.atlassian.com/proj.../browse/SEC-17

                  Comment


                  • #10
                    Also, Siteminder support has been added as per http://opensource2.atlassian.com/pro.../browse/SEC-35 and will be available in Acegi 0.9.0. Please let me know if anyone has questions about how to use the adapter.

                    Comment


                    • #11
                      Scott,

                      The Siteminder support feature looks interesting. We have been recently trying to integrate Siteminder with the J2EE security model. We want to have HTTP HEADERS produced by Siteminder translated into a proper remote user. We would like to be able to use getRemoteUser, getPrincipal, isUserInRole etc. of HttpServletRequest.

                      Can ACEGI be configured so that Siteminder protected web apps have access to getRemoteUser, getPrincipal, isUserInRole etc.?

                      Comment


                      • #12
                        Adam, the answer is most likely yes, depending on what you're sending through the Siteminder headers. If it's just a user's ID, you're good to go. If you also need to pass group membership, cost center, email address, etc., then you'll want to extend Acegi's Siteminder filter (as well as your AuthenticationDao implementation) to additionally process those headers. In the end Acegi's Siteminder filter doesn't do anything fancy - it just processes authentication requests from HTTP headers instead of form properties.

                        Comment


                        • #13
                          LdapAuthenticationProvider integration with Siteminder

                          I realize most of the posts here talk about extending the DaoAuthenticationProvider, but since I am getting my authorization roles from LDAP, can't I just extend the LdapAuthenticationProvider? This way I can just swap out the authentication mechanism from LDAP to Siteminder depending the environment and use the nifty declarative approach the LdapAuthenticationProvider affords.

                          However, I have attempted to use Acegi 1.0 Siteminder plug-in together with my extended LdapAuthenticationProvider, but no luck. Any suggestions?

                          Code:
                          	<bean id="authenticationProcessingFilter" class="com.xxx.xxx.common.security.SiteminderAuthenticationProcessingFilter">
                          	<property name="authenticationManager"><ref bean="authenticationManager"/></property>
                          	<property name="authenticationFailureUrl"><value>/accessDenied.jsp</value></property>
                          	<property name="defaultTargetUrl"><value>/jsp/Hello.jsp</value></property>
                          	<property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
                          	<property name="siteminderUsernameHeaderKey"><value>SM_USER</value></property>
                          	<property name="siteminderPasswordHeaderKey"><value>SM_USER</value></property>
                          	</bean>
                          ...
                          	<bean id="ldapAuthProvider"
                          		class="com.xxx.xxx.common.security.SiteminderLdapAuthenticationProvider">
                          		<constructor-arg>
                          			<bean
                          				class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
                          				<constructor-arg>
                          					<ref local="initialDirContextFactory"/>
                          				</constructor-arg>
                          				<property name="userDnPatterns">
                          					<list>
                          						<value>uid={0},ou=people</value>
                          					</list>
                          				</property>
                          			</bean>
                          		</constructor-arg>
                          		<constructor-arg>
                          			<bean
                          				class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
                          				<constructor-arg>
                          					<ref local="initialDirContextFactory"/>
                          				</constructor-arg>
                          				<constructor-arg>
                          					<value>ou=dl</value>
                          				</constructor-arg>
                          				<property name="groupRoleAttribute">
                          					<value>cn</value>
                          				</property>
                          			</bean>
                          		</constructor-arg>
                          	</bean>
                          Here's my simple code for the provider for userID/password equality as per the docs, since Siteminder already does authentication (just need LDAP for querying roles for authorization):

                          Code:
                          public class SiteminderLdapAuthenticationProvider extends
                                  LdapAuthenticationProvider {
                          
                              public SiteminderLdapAuthenticationProvider(LdapAuthenticator arg0,
                                      LdapAuthoritiesPopulator arg1) {
                                  super(arg0, arg1);
                              }
                          
                              protected final void additionalAuthenticationChecks(
                                      final UserDetails userDetails,
                                      final UsernamePasswordAuthenticationToken authentication)
                                      throws AuthenticationException {
                                  // Since siteminder does authentication, simply check that
                                  // the userid and password credentials match form siteminder.
                                  if (!userDetails.getUsername().equalsIgnoreCase(
                                          (String) authentication.getCredentials())) {
                                      throw new AuthenticationServiceException(
                                              "UserName and Password do not match.");
                                  }
                          
                              }
                          
                          }
                          Thanks in advance,

                          Comment


                          • #14
                            The doc regarding SiteminderAuthenticationProcessingFilter meant that you have to provide an AuthentificationProvider which does the check (userID=password) in the authenticate() method.
                            This method delegates to retrieveUser() from class AbstractUserDetailsAuthenticationProvider, thus from class LdapAuthenticationProvider.
                            You thus should redefine retrieveUser() instead of additionalAuthenticationChecks(). In retrieveUser(), you could simply ignore the authentication call and just invoke:

                            return createUserDetails(ldapUser, username, password);

                            The password may actually be anything.

                            Cheers,
                            -- Savrak

                            Comment


                            • #15
                              Thanks Savrak, but according to the javadocs, it shouldn't matter. It states: "Most of the time subclasses will not perform credentials inspection in this method, instead performing it in AbstractUserDetailsAuthenticationProvider.addition alAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken) so that code related to credentials validation need not be duplicated across two methods."

                              Also, I won't have an appropriate value to insert for the first parameter of that method, as it returns NullPointerException if I try the way you prescribed without a populated LdapUserDetails. This is because there is no way for me to get the LdapUserDetails without calling the authenticate method. But if I do that, authentication will fail because I don't have the password.

                              The only thing I can think is to do an LDAP search on the username by injecting my "usersearch" bean I have in the context into the SiteminderLdapAuthenticationProvider class. Then I can search and it will work, but is this the best approach?

                              Thanks,
                              Last edited by Loumeister; Jun 13th, 2006, 01:36 PM.

                              Comment

                              Working...
                              X