Announcement Announcement Module
Collapse
No announcement yet.
Spring Authentication With DWR Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    This is what i've put:

    Code:
        <bean id="securityService" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target">
                <bean class="org.siri.seguridad.SecurityServiceImpl">
                    <property name="authenticationManager"><ref bean="authenticationManager"/></property>
                </bean>
            </property>
            <property name="proxyInterfaces">
                <value>org.siri.seguridad.SecurityService</value>
            </property>
            <dwr:remote javascript="securityService"></dwr:remote>
        </bean>
    My AuthenticationManager instance is called 'authenticationManager', so the property ther does the work.

    For the logout part, using code from org.acegisecurity.ui.logout.SecurityContextLogoutH andler , we could do this:

    Code:
    	public void logout() {
     
    		// retrieve HttpServletRequest request, HttpServletResponse response, Authentication authentication
    		// i don't like this implementation, but it is what it came to my mind for now, i don't like to depend to httpServletRequest, i just would like to do this with SecurityContext
    
    		HttpSession session = request.getSession(false);
    		if (session != null) {
    			session.invalidate();
    		}
    
    		SecurityContextHolder.clearContext();
    	}
    I think i'm forgetting to save the authorization object in the securityContext.
    Or perhaps we don't have to use AuthenticationManager but other class...
    I'm looking into it.

    Regards

    Comment


    • #17
      Originally posted by nickar View Post
      This is what i've put:

      Code:
          <bean id="securityService" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="target">
                  <bean class="org.siri.seguridad.SecurityServiceImpl">
                      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
                  </bean>
              </property>
              <property name="proxyInterfaces">
                  <value>org.siri.seguridad.SecurityService</value>
              </property>
              <dwr:remote javascript="securityService"></dwr:remote>
          </bean>
      My AuthenticationManager instance is called 'authenticationManager', so the property ther does the work.

      For the logout part, using code from org.acegisecurity.ui.logout.SecurityContextLogoutH andler , we could do this:

      Code:
      	public void logout() {
       
      		// retrieve HttpServletRequest request, HttpServletResponse response, Authentication authentication
      		// i don't like this implementation, but it is what it came to my mind for now, i don't like to depend to httpServletRequest, i just would like to do this with SecurityContext
      
      		HttpSession session = request.getSession(false);
      		if (session != null) {
      			session.invalidate();
      		}
      
      		SecurityContextHolder.clearContext();
      	}
      I think i'm forgetting to save the authorization object in the securityContext.
      Or perhaps we don't have to use AuthenticationManager but other class...
      I'm looking into it.

      Regards
      You are using a lot of namespaces in your configs !!! (i'm more a spring 1.0/2.0 person ).
      I've found out in org.acegisecurity.ui.AbstractProcessingFilter that after authentication it calls this method this:
      Code:
      	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
      			Authentication authResult) throws IOException {
      //...
      		SecurityContextHolder.getContext().setAuthentication(authResult);
      
      //...
      		rememberMeServices.loginSuccess(request, response, authResult);
      
      //...
      	}
      So..., what we where forgetting was to add setAuthentication!!!
      I've modified the code, and i've already tested it.

      This is what i've written:
      Code:
      package org.siri.seguridad;
      
      public interface SecurityService {
      
      	public String[] authenticate(String username, String password);
      }
      Code:
      package org.siri.seguridad;
      
      import org.acegisecurity.Authentication;
      import org.acegisecurity.AuthenticationManager;
      import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
      import org.acegisecurity.GrantedAuthority;
      import org.acegisecurity.context.SecurityContextHolder;
      
      public class SecurityServiceImpl implements SecurityService {
      
      	AuthenticationManager authenticationManager;
      
      	public AuthenticationManager getAuthenticationManager() {
      		return authenticationManager;
      	}
      
      	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
      		this.authenticationManager = authenticationManager;
      	}
      
      	public String[] login(String username, String password) {
      
              Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
              authentication = authenticationManager.authenticate(authentication);
      
              SecurityContextHolder.getContext().setAuthentication(authentication);
      
              GrantedAuthority[] ga = authentication.getAuthorities();
              String[] retA = new String[ga.length];
      
              for (int i = 0; i < ga.length; i++)
                  retA[i] = (String) ga[i].toString();
      
         		return retA;
      	}
      
      	public void logout() {
               SecurityContextHolder.getContext().setAuthentication(null);
      	}
      }
      Code:
          <dwr:configuration>
              <dwr:convert type="object" class="org.acegi.GrantedAuthorityImpl"/>
      <!--SNIP-->
          </dwr:configuration>
          <bean id="securityService" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="target">
                  <bean class="org.siri.seguridad.SecurityServiceImpl">
                      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
                  </bean>
              </property>
              <property name="proxyInterfaces">
                  <value>org.siri.seguridad.SecurityService</value>
              </property>
              <dwr:remote javascript="securityService"></dwr:remote>
          </bean>
      It does the trick.

      Comment


      • #18
        Do you mean save the authentication object in the security context?

        Here:
        http://static.springframework.org/sp...-overview.html

        It says:
        The security context is established by calling SecurityContextHolder.getContext().setAuthenticati on(...), passing in the returned authentication object.

        Comment


        • #19
          Originally posted by ole.ersoy View Post
          Do you mean save the authentication object in the security context?

          Here:
          http://static.springframework.org/sp...-overview.html

          It says:
          I have already done that!
          I've tested it also, and it is working!!!
          I've changed it a bit, here it is the code:
          Code:
          package org.siri.seguridad;
          
          public interface SecurityService {
          	public boolean login(String username, String password);
          	public String[] getAuthorities();
              public void logout();
          }
          Code:
          package org.siri.seguridad;
          
          import org.acegisecurity.Authentication;
          import org.acegisecurity.AuthenticationManager;
          import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
          import org.acegisecurity.GrantedAuthority;
          import org.acegisecurity.context.SecurityContextHolder;
          
          public class SecurityServiceImpl implements SecurityService {
          
          	AuthenticationManager authenticationManager;
          
          	public AuthenticationManager getAuthenticationManager() {
          		return authenticationManager;
          	}
          
          	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
          		this.authenticationManager = authenticationManager;
          	}
          
          	public boolean login(String username, String password) {
                  Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
                  authentication = authenticationManager.authenticate(authentication);
                  if (authentication.isAuthenticated()) {
                      SecurityContextHolder.getContext().setAuthentication(authentication);
                      return true;
                  };
                  return false;
              }
          
          	public String[] getAuthorities() {
                  GrantedAuthority[] ga = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
                  String[] retA = new String[ga.length];
                  for (int i = 0; i < ga.length; i++)
                      retA[i] = (String) ga[i].toString();
          
             		return retA;
              }
          
              public void logout() {
                   SecurityContextHolder.getContext().setAuthentication(null);
          	}
          }
          Any reason to return authorities instead of boolean ? or the other way?

          Regards,

          Comment


          • #20
            Awesome - I got it working as well. Here's what I have so far:

            Code:
            package com.example.security.impl;
            
            import org.springframework.security.Authentication;
            import org.springframework.security.AuthenticationManager;
            import org.springframework.security.context.SecurityContextHolder;
            import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
            
            import com.example.security.IAuthenticationService;
            
            public class AuthenticationServiceImpl implements IAuthenticationService
            {
            	AuthenticationManager authenticationManager;
            
            	public AuthenticationManager getAuthenticationManager() 
            	{
            		return authenticationManager;
            	}
            
            	public void setAuthenticationManager(AuthenticationManager authenticationManager) 
            	{
            		this.authenticationManager = authenticationManager;
            	}
            
            	public boolean login(String username, String password) 
            	{
            		Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
                    authentication = authenticationManager.authenticate(authentication);
                    if (authentication.isAuthenticated()) {
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                        return true;
                    };
                    return false;
            	}
            
            	public void logout() 
            	{
            		SecurityContextHolder.getContext().setAuthentication(null);
            	}
            }
            As you can see I have broken SecurityService up into:
            - IAuthenticationService
            - IAuthorizationService

            I think it's cleaner to separate the two concerns like that.

            The second thing is that Spring throws a org.springframework.security.BadCredentialsExcepti on runtime exception when the credentials don't authenticate. Therefore the login method will never return false.

            We could catch this and return false, but I wonder if there's a point to it?

            We need a try catch block on the javascript client side either way, in the event of some other exception. I think it would be sexier to just have have a void return type, and if no exception is thrown the user is logged in. If an exception is thrown, then we have to check the type. If it's a org.springframework.security.BadCredentialsExcepti on then the user must try again. Otherwise the user has to be notified that the authentication system is down.

            I need to review my DWR exception translation notes, to see whether we can distinguish exceptions on the client side. I'm pretty sure we can.

            Comment


            • #21
              OK - So I changed the login method to looks like this:

              public void login(String username, String password)
              {
              Authentication authentication =
              new UsernamePasswordAuthenticationToken(
              username,
              password);

              authentication =
              authenticationManager.
              authenticate(authentication);

              if (authentication.isAuthenticated())
              {
              SecurityContextHolder.getContext().setAuthenticati on(authentication);
              };
              }
              I catch the exceptions on the client side like this:
              Code:
                  var authenticationErrorHandler = function(errorString, exception) 
                  {
                  	  console.log("This execption occurred: " + exception.javaClassName);
                        console.log("ERROR STRING IS: " + errorString);
                        if (exception.javaClassName == "org.springframework.security.BadCredentialsException")
                        {
                            console.log("This occurred: org.springframework.security.BadCredentialsException");
                        }
              		  else
              		  {
              			console.log("Authentication Service Offline.  Try later.");
              		  }
                  };
              
                  var authenticationCallParameters = 
                  {
                    async: false,
                    callback: function() {console.log("Authentication Attempted");},
                    errorHandler:this.authenticationErrorHandler
                  }
              
                  AuthenticationService.login(
                  		"ole", 
              			"olespassword", 
              			authenticationCallParameters);
              	
                  AuthenticationService.login(
                  		"ole", 
              			"wrongpassword",
              			authenticationCallParameters);
              I think DWR automatically converts subclasses of java.lang.exception with the following in the configuration file:

              Code:
              	<dwr:configuration>
              	    <dwr:convert type="exception"
              	     			 class="java.lang.Exception">
              	    </dwr:convert>
              	</dwr:configuration>

              Comment


              • #22
                Just tested getting authorizations as well:

                Code:
                	var printRoles = function(/*String[]*/ roles)
                	{
                		for (role in roles)
                		{
                			console.log("Role: " + roles[role]);
                		}
                	}
                	
                    var authorizationCallParameters = 
                    {
                      async: false,
                      callback: this.printRoles
                    }
                			
                	AuthorizationService.getAuthorities(
                		authorizationCallParameters);
                Seems to be working fine.

                I guess that's it. Should we put a note out on the DWR mailing list? I'd be happy to do it, unless you want to?

                Comment


                • #23
                  Incidentally I also tested logout:

                  Code:
                      var authorizationErrorHandler = function(errorString, exception) 
                      {
                      	  console.log("This execption occurred: " + exception.javaClassName);
                            console.log("ERROR STRING IS: " + errorString);
                            if (exception.javaClassName == "java.lang.NullPointerException")
                            {
                                console.log("java.lang.NullPointerException thrown when trying to get authorities");
                            }
                  		  else
                  		  {
                  			console.log("Authorization Service Offline.  Try later.");
                  		  }
                      };
                  	
                      var authorizationCallParameters = 
                      {
                        async: false,
                        callback: this.printRoles,
                  	  errorHandler: this.authorizationErrorHandler
                      }
                  			
                  	AuthorizationService.getAuthorities(
                  		authorizationCallParameters);
                  		
                      AuthenticationService.logout();
                  	
                  	AuthorizationService.getAuthorities(
                  		authorizationCallParameters);
                  It works as expected.

                  Comment


                  • #24
                    I didn't saw your code on getAuthorities.
                    I'm having some trouble with the serialization of GrantedAuthority objects.
                    What's your dwr config for that?

                    Just to kick off another aproach to this, perhaps would be usefull to create a method to test 'callability' of methods.
                    Something like SecurityService.isCallingAllowed(method).
                    What do you think?

                    You can write to dwr mailling list if you want.
                    Perhaps answer to my thread on this!

                    Regards and congrats to both of us !

                    Comment


                    • #25
                      I kept the Authorization code the same.

                      Code:
                      package com.example.security.authorization;
                      
                      public interface IAuthorizationService 
                      {
                      	public String[] getAuthorities();
                      }
                      
                      
                      package com.example.security.authorization.impl;
                      
                      import org.springframework.security.GrantedAuthority;
                      import org.springframework.security.context.SecurityContextHolder;
                      
                      import com.example.security.authorization.IAuthorizationService;
                      
                      public class AuthorizationServiceImpl implements IAuthorizationService
                      {
                      	public String[] getAuthorities() 
                      	{
                              GrantedAuthority[] grantedAuthorities = 
                              	SecurityContextHolder.
                              	getContext().
                              	getAuthentication().
                              	getAuthorities();
                              
                              String[] authorities = 
                              	new String[grantedAuthorities.length];
                              
                              for (int i = 0; i < grantedAuthorities.length; i++)
                                  authorities[i] = 
                                  	(String) grantedAuthorities[i].toString();
                      
                         		return authorities;
                          }
                      }
                      I expose the AuthorizationService like this:

                      Code:
                          <bean
                           id="authorizationServiceImpl"
                           class="com.example.security.authorization.impl.AuthorizationServiceImpl">
                              <dwr:remote
                               javascript="AuthorizationService">
                              </dwr:remote>
                          </bean>
                      Does that work for you?

                      One could do something like:
                      Code:
                      if (hasRole(user, role))
                      {
                      //Call DWR Proxy
                      
                      
                      }
                      Where the hasRole method just checks the users authorities against the provide role arguement, before a method is called. Ideally I think the user interface should disable controls that the user cannot interact with due to missing authorities.

                      Service layer security on the server side should also be applied, in case someone hacks the user interface.

                      Comment


                      • #26
                        But with the hasRole implementation you are not checking against the methods' aclManager!
                        I was talking about something that tests if a principal can invoke one service, just to adjust the ui as we where talking before.
                        If not, we are just crying over the spoiled milk ,
                        I'm looking into it.
                        Regards,

                        Comment


                        • #27
                          Sorry - The ACL manager concept is new to me. How is that different from checking the authorities?

                          So a more flushed out way of doing it would be to gather say all the dojo widgets in a list, and then post authentication, have a process that goes through and enables / disables widgets per the authorizations the principal owns, using a similar type of hasRole call. So the client application would need to have previous knowledge of what methods are allowed to be called by what roles, and which widgets call those methods. So:

                          - Get a list of all widgets
                          - For each widget
                          - Check to see whether widgets makes proxy call
                          - If widgets makes a proxy call, check to see whether principal is authorized to make call
                          - If not disable widget

                          Comment


                          • #28
                            Hang on...is this what the ACL Manager does?

                            ....So the client application would need to have previous knowledge of what methods are allowed to be called by what roles,...

                            Comment


                            • #29
                              I am reading the api, i don't know how to do this already.
                              I don't like the idea of widget authorization.
                              I would prefer to authorize the methods used by sending a list of names to the server.
                              What do you think?

                              Comment


                              • #30
                                First I would protect all the methods using the AccessDecisionManager. See for example section 2.4.2 here:

                                http://forum.springsource.org/newrep...ote=1&p=244955

                                Then I would consider protecting them on the client side as well, mimicking the AccessDecisionManager logic on the client side, so that more informative message can be given. Could just catch the AccessDecisionManager exceptions as well....

                                Comment

                                Working...
                                X