Announcement Announcement Module
Collapse
No announcement yet.
Acegi & Tapestry: A Step-by-Step Guide Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Acegi & Tapestry: A Step-by-Step Guide

    If you've read a couple of my last (unanswered) posts, you'll see that I was flailing on getting Acegi and Tapestry to play nicely together-- mostly due to the fact that (a) I'm a noob and (b) Tapestry URLs are all /app?page=Blah...which makes it impossible to distinguish between a Login page you want unsecured and another page you do want secured.

    So, with the caveat that there may be a lot of unnecessary configuration garbage I'm about to post, I thought I'd share the steps I went through to get this working.

    My environment is: Eclipse 3.1.1, Java 5, Tapestry 4, Acegi 1.0.0 RC2, Tomcat 5.5.12

  • #2
    Step 1) Enable Friendly URLs in Tapestry

    Before trying to get Acegi set up on your Tapestry application, you should first enable Friendly URLs to allow fine-grained control of pattern matching in the Acegi objectionDefinitionSource widgets.

    Most of these instructions are stolen right out of Kent Tong Tap 4 manual.

    Step A: Edit your hivemodule.xml file
    Add this contribution:
    Code:
    	<contribution configuration-id="tapestry.url.ServiceEncoders">
    		<page-service-encoder id="page" extension="html" service="page"/>
    		<direct-service-encoder id="direct" stateless-extension="direct" stateful-extension="sdirect"/>
    		<extension-encoder id="extension" extension="svc" after="*"/>
    	</contribution>
    Step B: Edit your web.xml file
    In addition to the standard "/app" mapping, add the url-patterns shown here. Tapestry uses a variety of different url translations to achieve direct links, services, etc. through the friendly-url paradigm.
    Code:
    <servlet-mapping>
            <servlet-name>edis3-admin</servlet-name>
            <url-pattern>/app</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>edis3-admin</servlet-name>
            <url-pattern>*.html</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>edis3-admin</servlet-name>
            <url-pattern>*.direct</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>edis3-admin</servlet-name>
            <url-pattern>*.sdirect</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>edis3-admin</servlet-name>
            <url-pattern>*.svc</url-pattern>
        </servlet-mapping>

    Comment


    • #3
      Step 2) Add Acegi Spring configurations

      This is bulk of the effort here, but it's mostly just XML file editing and small configuration differences to fit in your environment.

      Step A: Add Acegi configurations to your web.xml
      Add this filter and then map it to your application. Note that many examples you may see will have the targetClass defined to be AuthenticationProcessingFilter...don't use that one; it's just a subset of the larger filter chain we'll set up in our application context.
      Code:
         
          <!-- Note: this replaces your original Tapestry filter and filter-mapping -->
          <filter>
              <filter-name>Acegi Filter Chain Proxy</filter-name>
              <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
              <init-param>
                  <param-name>targetClass</param-name>
                  <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
              </init-param>
          </filter>	 		
          <filter-mapping>
            <filter-name>Acegi Filter Chain Proxy</filter-name>
            <url-pattern>/*</url-pattern>
          </filter-mapping>
      Still in the web.xml, add an additional file (in my case, application-context-acegi.xml) to your contextConfigLocation that we'll use to store the Acegi configuration information. I also found it necessary to intercept the 403 error code to provide seamless integration with my application when someone hits and a page they're not authorized to see.

      Code:
      	<context-param>
      		<param-name>contextConfigLocation</param-name>
      		<param-value>classpath:edis3-ws-client-context.xml, classpath:application-context-acegi.xml</param-value>
      	</context-param>
      	
      	<error-page>
      		<error-code>403</error-code>
      		<location>/AccessDenied.html</location>
      	</error-page>
      Step B: Create the application-context-acegi.xml file
      I created a new file in the WEB-INF/classes location of my project and added the following configuration settings, which I've commented in the code:
      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
      
      <beans>
      
         <!-- ======================== FILTER CHAIN ======================= -->
      
      	<!--  Note: I got rid of the 'rememberMe' and 'switchUser' filters you see in a lot of examples.  They were confusing the debugging, and now that I understand what's going on, they'll be easy to add in later if I need them -->
      	<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
            <property name="filterInvocationDefinitionSource">
               <value>
      		    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      		    PATTERN_TYPE_APACHE_ANT
                  /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
               </value>
            </property>
          </bean>
      
         <!-- ======================== AUTHENTICATION ======================= -->
      
         <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
            <property name="providers">
               <list>
                  <ref local="daoAuthenticationProvider"/>
                  <ref local="anonymousAuthenticationProvider"/>
               </list>
            </property>
         </bean>
      
       <!--  NOTE NOTE NOTE NOTE      BE CAREFUL HERE
               The inMemoryDaoImpl DOES NOT support the passwordEncoder -->
      	<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
      		<property name="userMap">
      			<value>
      				tom=tvaughan,ROLE_USER,ROLE_SYSTEM_ADMIN
      				sue=stillery,ROLE_USER,ROLE_SYSTEM_ADMIN				
      				carlos=cfernandez,ROLE_USER,ROLE_USER_ADMIN
      				joel=jmoeller,ROLE_USER,ROLE_USER_ADMIN
      				tony=tgiaccone,ROLE_USER,ROLE_SERVICE_LIST_ADMIN
      				jack=jrodriguez,ROLE_USER,ROLE_INVESTIGATION_ADMIN
      				walter=wkelly,ROLE_USER,ROLE_INVESTIGATION_MGR
      				anonymous=anonymous,
      			</value>
      		</property>
      	</bean>
      
         <!-- define, but don't use until you're ready to attach to a non-inMemoryDao -->
         <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
      
         <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
      	  <property name="userDetailsService"><ref local="inMemoryDaoImpl"/></property>
      
         </bean>
         <!-- InMemoryDao doesn't encode passwords...it's gotta be plaintext -->
         <!--       <property name="passwordEncoder"><ref local="passwordEncoder"/></property> -->
      
      
         <!-- Automatically receives AuthenticationEvent messages -->
         <bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>
      
         <bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
            <property name="authenticationManager"><ref local="authenticationManager"/></property>
            <property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
         </bean>
      
         <!-- Essentially Unused unless you're using Basic Authentication, which we're not -->
         <bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
            <property name="realmName"><value>Contacts Realm</value></property>
         </bean>
      
         <bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
            <property name="key"><value>foobar</value></property>
            <property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property>
         </bean>
      
         <bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
            <property name="key"><value>foobar</value></property>
         </bean>
      
         <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
         </bean>
      
      
         <!-- ===================== HTTP REQUEST SECURITY ==================== -->
      
         <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
            <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
         </bean>
      
         <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
            <property name="authenticationManager"><ref bean="authenticationManager"/></property>
            <property name="authenticationFailureUrl"><value>/LoginFailed.html</value></property>
            <property name="defaultTargetUrl"><value>/Home.html</value></property>
            <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
         </bean>
      
         <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
            <property name="loginFormUrl"><value>/Login.html</value></property>
            <property name="forceHttps"><value>false</value></property>
         </bean>
      
         <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
            <property name="allowIfAllAbstainDecisions"><value>false</value></property>
            <property name="decisionVoters">
               <list>
                  <ref bean="roleVoter"/>
               </list>
            </property>
         </bean>
      
         <!-- An access decision voter that reads ROLE_* configuration settings -->
         <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>   
         
      
         <!-- Note the order that entries are placed against the objectDefinitionSource is critical.
              The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.
              Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->			               		        
         <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
            <property name="authenticationManager"><ref bean="authenticationManager"/></property>
            <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
            <property name="objectDefinitionSource">
               <value>			   	          
               		PATTERN_TYPE_APACHE_ANT
               		/media/*=ROLE_ANONYMOUS,ROLE_USER
               		/styles/*=ROLE_ANONYMOUS,ROLE_USER
               		/AccessDenied.html*=ROLE_ANONYMOUS,ROLE_USER
               		/Login.html*=ROLE_ANONYMOUS,ROLE_USER
               		/Logout.html*=ROLE_ANONYMOUS,ROLE_USER
               		/Login,loginForm.sdirect*=ROLE_ANONYMOUS,ROLE_USER
               		/LoginFailed.html*=ROLE_ANONYMOUS,ROLE_USER
               		/Home.html*=ROLE_ANONYMOUS,ROLE_USER
               		/asset.svc*=ROLE_ANONYMOUS,ROLE_USER
               		/ManageUsers.html*=ROLE_SYSTEM_ADMIN,ROLE_USER_ADMIN
               		/**=ROLE_USER
               </value>
            </property>
         </bean>
      </beans>
      Some notes about this configuration:
      1) If you don't create a generic "ROLE_USER" to define someone who isn't anonymous, then you need to add every single role to every single pattern in your filterInvocationInterceptor. That's a pain, so I just have every user defined to be a member of ROLE_USER in addition to their "real" role (e.g. ROLE_SYSTEM_ADMIN).

      2) I can't emphasize the passwordEncoder gotchya enough...I lost a whole day trying to figure out why I kept getting redirected to the login page after I swear I correctly logged in. For the purposes of getting up and running, it's easy to use the inMemoryDaoImpl, but just be sure to comment out the use of the PasswordEncoder that you may have cut & pasted from demo code you'll find on this board and others.

      Comment


      • #4
        Step 3) Create a Login page

        If you're using a branding template (i.e. Border component), it's a good idea to comment it out as you're getting set up because Acegi will log the hell out of attempts to access images, javascript, stylesheets, etc.

        Step A: Add the HTML page to your WEB-INF
        Code:
        <html jwcid="$content$">
        <!-- body jwcid="@branding:BaseBorder" -->
        <body>
        <h4>EDIS3 Login</h4>
        
        <p class="errorMessage"><span jwcid="errorMsg"/></p>
        <p>Please login:</p>
        
        	<form jwcid="loginForm">
        	  <table border="0">
        	    <tr><td>Username:</td><td><input type="text" jwcid="username"/></td></tr>
        	    <tr><td>Password:</td><td><input type="password" jwcid="password"/></td></tr>
        	    <tr><td>&nbsp;</td><td><input type="submit" value="Login"/></td></tr>
        	  </table>
        	</form>
        <pre>
        &lt;property name="userMap"&gt;
          &lt;value&gt;
        	tom=tvaughan,ROLE_USER,ROLE_SYSTEM_ADMIN
        	sue=stillery,ROLE_USER,ROLE_SYSTEM_ADMIN				
        	carlos=cfernandez,ROLE_USER,ROLE_USER_ADMIN
        	joel=jmoeller,ROLE_USER,ROLE_USER_ADMIN
        	tony=tgiaccone,ROLE_USER,ROLE_SERVICE_LIST_ADMIN
        	jack=jrodriguez,ROLE_USER,ROLE_INVESTIGATION_ADMIN
        	walter=wkelly,ROLE_USER,ROLE_INVESTIGATION_MGR
        	anonymous=anonymous,
          &lt;/value&gt;
        &lt;/property&gt;	
        </pre>
        	
        <style type="text/css">
        .security_debugging {
          background-color: silver;
          margin: 1em;
          padding: 1em;
          border: 1px dashed black;
        }
        </style>
        <div class="security_debugging">
        <p>Current Authentication Information:<br/>
        User: <span jwcid="user"><strong>user</strong></span><br/>
        Details: <span jwcid="details" raw="true">details</span><br/>
        </p>
        </div>
        	
        </body>
        </html>
        Step B: Define the Login.page file
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE page-specification PUBLIC
          "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
          "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
        
        <page-specification class="gov.usitc.edis.pages.Login">
        
            <description>EDIS Login</description>
        
            <meta key="page-title" value="EDIS Login"/>
        	
         	<component id="loginForm" type="Form">
         	  <binding name="listener" value="listener:login"/>
         	</component>
         	<component id="username" type="TextField">
         	  <binding name="value" value="username"/>
         	</component>
        	<component id="password" type="TextField">
         	  <binding name="value" value="password"/>
         	  <binding name="hidden" value="true"/>
         	</component> 	
         	<component id="errorMsg" type="Delegator">
         	  <binding name="delegate" value="beans.delegate.firstError"/>
         	</component>
         	<component id="user" type="Insert">
         		<binding name="value" value="user"/>
         	</component>
         	<component id="details" type="Insert">
         		<binding name="value" value="details"/>
         	</component>  	
        </page-specification>
        Step C: Add the Login.java file to your source tree
        Code:
        package gov.usitc.edis.pages;
        
        import org.acegisecurity.Authentication;
        import org.acegisecurity.GrantedAuthority;
        import org.acegisecurity.context.SecurityContextHolder;
        import org.apache.commons.logging.Log;
        import org.apache.commons.logging.LogFactory;
        import org.apache.tapestry.IRequestCycle;
        import org.apache.tapestry.RedirectException;
        import org.apache.tapestry.html.BasePage;
        import org.apache.tapestry.valid.ValidationDelegate;
        
        import org.apache.tapestry.annotations.Bean;
        import org.apache.tapestry.annotations.InjectObject;
        import org.apache.tapestry.event.PageBeginRenderListener;
        import org.apache.tapestry.event.PageEvent;
        
        
        
        public abstract class Login extends BasePage implements PageBeginRenderListener {
            
        	@SuppressWarnings("unused")
        	private final static Log LOG = LogFactory.getLog(Login.class);	
        	   
        	private String username;
        	private String password;
        	
        	@Bean
        	public abstract ValidationDelegate getDelegate();
        	
        	public void login(IRequestCycle cycle) throws RedirectException {
        	    String acegiUrl = cycle.getAbsoluteURL("/j_acegi_security_check?j_username="+getUsername()+"&j_password="+getPassword());
        	    LOG.info("Throwing redirect exception to '" + acegiUrl + "'");
                throw new RedirectException(acegiUrl);		
        	}	
        	
            public void pageBeginRender(PageEvent event){
        
            }
            
            public String getUser() {
            	Authentication myAuth = SecurityContextHolder.getContext().getAuthentication();
            	return myAuth.getName();
            }
            
            public String getDetails() {
            	Authentication myAuth = SecurityContextHolder.getContext().getAuthentication();
            	if(myAuth == null) {
            		return "Authorization object is null";
            	} else {
            		StringBuffer b = new StringBuffer();
            		b.append("<ul>");
            		b.append("  <li>principal = " + myAuth.getPrincipal() + "</li>");
            		b.append("  <li>credentials = " + myAuth.getCredentials() + "</li>");
            		b.append("  <li>isAuthenticated = " + myAuth.isAuthenticated() + "</li>");
            		b.append("  <li>Granted Authorities = ");
            		GrantedAuthority[] gas = myAuth.getAuthorities();
            		for(int i=0; i<gas.length; i++) {
            			b.append(gas[i] + " ");
            		}
            		b.append("</li>");
            		b.append("  <li>Details = " + myAuth.getDetails() + "</li>");
            		b.append("  <li>Class = " + myAuth.getClass() + "</li>");    		
            		b.append("</ul>");
            		//return myAuth.toString();
            		
            		return b.toString();
               	}
            }
           
        
        
        	public String getPassword() {
        		return password;
        	}
        
        	public void setPassword(String password) {
        		this.password = password;
        	}
        
        	public String getUsername() {
        		return username;
        	}
        
        	public void setUsername(String username) {
        		this.username = username;
        	}   
        }

        Comment


        • #5
          Step 4) Add additional support pages

          In the Acegi configuration context file from Step #2, you'll find references to "LoginFailed.html" and "Logout.html", and in the web.xml, there's a reference to "AccessDenied.html".

          Using the same basic code for the Login page, flush out the other pages.

          Because I'm still in the development phase of this project, I find it pretty helpful to put some SecureContext/Authentication display at the bottom of these pages so I know what the current authentication looks like and so I can verify expected behavior.

          Comment


          • #6
            Step 5) Testing, Logging

            I was playing around with trying to get some meaningful JUnit tests on my application working yesterday and wasn't having much success...it's pretty complicated to spool up a simple test, and even then I'm not sure unit testing is what I should be doing--- this seems more like in the realm of functional or possibly integration testing using tools other than JUnit. Stay tuned.

            I found that I learned a lot about the Acegi flow of control by turning up debugging...just add this to your log4j.properties files and follow along; just be sure to remove your branding assets from your page first.

            Code:
            log4j.logger.org.acegisecurity=DEBUG

            Comment


            • #7
              Thanks for sharing all of this, Tom.

              Comment


              • #8
                No, thank YOU

                Seriously, Ben...this framework is really impressive. Thanks so much for all your hard work and evangalism in getting this out there. You're a credit to the open source community.

                Comment


                • #9
                  Tom,

                  Very nice presentation the the steps. Since I am a tapestry newbie, I am not quite sure how you hand the user into the Tapestry context. I have gone through your steps and added the required configs into a simple tapestry environment. I do get to the acegi login page, but when i enter the credentials, i am redirected back to the login page and my session is still tagged as anonymous.

                  So it seems like i am either not logged in, or once I am logged in, how do i get the user credentials into my tapestry application?

                  thanks is advance!
                  -jason

                  Comment


                  • #10
                    Tapestry doesn't need to know about the User's Security Context

                    Hi,

                    Tapestry is completely oblivious to the presence of Acegi...Acegi operates at the URL request level, before Tapestry even tries to respond to a request.

                    If you keep getting the login page with your credentials showing up as "Anonymous", make sure you aren't using a PasswordEncoder if you have an InMemoryDaoImpl as your AuthenticationProvider...

                    In the application I'm working on right now, we have our own business object named "EdisUser" that has the username, address, phone number, etc. in it that is completely independent of Acegi. We use Acegi to challenge you at the login page. Assuming you login correctly, we then go an grab your EdisUser object out of the DB and "do stuff" with that POJO. If we need to check your permission to do something, we can grab your logged-in/valid authentication object from Acegi's SecurityContext, but it's rare that we need to do that.

                    The only real touch point between Tapestry and Acegi in the login use case is if you use Tapestry to handle the form component on the Login.html page. In my situation, my username field is called "username" and my password field is called "password." Those fields are components defined in the Login.page file which uses the Login.java object as a backing POJO.

                    My form submit in Login.java looks like this:
                    Code:
                    	
                    public void login(IRequestCycle cycle) throws RedirectException {
                      	   String ciphertext = getCipherText(getPassword());
                    		
                    	    String acegiUrl = cycle.getAbsoluteURL(
                    	    		"/j_acegi_security_check?j_username=" +
                    	    		getUsername() +
                    	    		"&j_password=" +
                    	    		ciphertext);
                    	    LOG.info("Throwing redirect exception to '" + acegiUrl + "'");
                    	    
                                throw new RedirectException(acegiUrl);		
                    }
                    So you see that Tapestry basically assembles a servlet-style URL and throws a redirect exception to that url. In the web.xml, that /j_acegi_security_check is listened for and winds up in the authenticationProcessingFilter defined in my application-context.xml file.

                    Comment


                    • #11
                      Tom,

                      Thanks for replying.

                      So how does Tapestry becomse aware of the username that was entered into the login form? Can you explain what should happen after a successful login?
                      Where do you take the username and fetch the EdisUser

                      thanks again!
                      -jason

                      Comment


                      • #12
                        It's a pass-through

                        Originally posted by yazsaw7
                        Tom,

                        Thanks for replying.

                        So how does Tapestry becomse aware of the username that was entered into the login form? Can you explain what should happen after a successful login?
                        Where do you take the username and fetch the EdisUser

                        thanks again!
                        -jason
                        Hey Jason,

                        Tapestry is aware of the username and password because Tapestry is responsible for rendering and processing the login form. So on the Login.html page, you'll see code like this:
                        Code:
                        	<form jwcid="loginForm">
                        	  <table border="0">
                        	    <tr><td>Username:</td><td><input type="text" jwcid="username"/></td></tr>
                        	    <tr><td>Password:</td><td><input type="password" jwcid="password"/></td></tr>
                        	    <tr><td>&nbsp;</td><td><input type="submit" value="Login"/></td></tr>
                        	  </table>
                        	</form>
                        Notice that the jwcid of the fields are not j_username and j_password.

                        When a user fills in those fields and posts the form, tapestry routes the strings down to the Login.java class for processing. In my case, it's the "login" method that handles that form posting.

                        In the login() method, I finesse the username and password strings** and then throw a redirect exception to the servlet that Acegi is listening to:

                        Code:
                            String acegiUrl = cycle.getAbsoluteURL(
                                "/j_acegi_security_check?j_username=" +
                                getUsername() +
                                "&j_password=" +
                                ciphertext);
                            LOG.info("Throwing redirect exception to '" + acegiUrl + "'");
                        	    
                            throw new RedirectException(acegiUrl);
                        Note that in the 'acegiUrl' I am using the j_username and j_password parameter names.

                        Ok, so Acegi sees that post to the j_acegi_security_check servlet (mapped in the web.xml file, remember) and goes and does its thing. Assuming the login was valid, it then redirects the user to whatever your 'defaultTargetUrl' value is. Mine is configured like this:

                        Code:
                           <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
                              <property name="authenticationManager"><ref bean="authenticationManager"/></property>
                              <property name="authenticationFailureUrl"><value>/LoginFailed.html</value></property>
                              <property name="defaultTargetUrl"><value>/Home.html</value></property>
                              <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
                           </bean>
                        So now the user is looking at the Home.html page, rendered courtesy of Tapestry. That page was backed by the Home.java class. If the Home.java class needs to get that user's info, it can make a call like this (for example):

                        Code:
                            public void pageBeginRender(PageEvent event){    
                                Authentication myAuth = 
                                     SecurityContextHolder.getContext().getAuthentication();
                            	if(myAuth == null) {
                            	    LOG.info("Authorization object is null");
                            	} else {
                                    String name = myAuth.getName();
                                    EdisUser currentUser = getUserByName(name);
                                    // now do stuff with my EdisUser business object
                            	}
                            }
                        Hope this helps,
                        Tom

                        **= in my situation, I encrypt the password with the Md5Encoder before sending it to the j_acegi_security_check servlet. Check out hispacta.blogspot.com if you're curious as to why.

                        Comment


                        • #13
                          String acegiUrl = cycle.getAbsoluteURL(
                          "/j_acegi_security_check?j_username=" +
                          getUsername() +
                          "&j_password=" +
                          ciphertext);
                          LOG.info("Throwing redirect exception to '" + acegiUrl + "'");

                          throw new RedirectException(acegiUrl);

                          Isnt this transforming POST request into GET request? And exposing passwords into application access log files?

                          Comment


                          • #14
                            Exposing passwords and log files

                            We remove the LOG.info line for our production code.

                            In terms of exposing the password, it does send the request with the MD5-encrypted password, which would be useless to someone who would try to use it to log in to the application via the GUI (because the authentication attempt would result in an MD5 encryption of the MD5 encryption of the real password).

                            If you hacked through our firewalls, got access to our web services box, captured the username and MD5 password, wrote your own application that utilized the username and password to create a Authentication token from our services, deployed that application to our application server, and then utilized the other web services to do malicious stuff, then it'd be a problem.

                            Of course, if you could do all that stuff you can probably think of an easier way to wreck havoc.

                            Comment


                            • #15
                              Hi! One more question;
                              getCipherText method?
                              How does that work?

                              Comment

                              Working...
                              X