Results 1 to 3 of 3

Thread: Subverting DI so a password can be entered by the user

  1. #1
    Join Date
    Jul 2006
    Posts
    17

    Default Subverting DI so a password can be entered by the user

    I have set up a 'secure' HttpInvoker invoked service call that works fine. It is as per pages 586-588 of the Pro Spring book. My problem with it is that the password is in a config file (actually it will be a resource in a jar but that's not a secure place for it to be either). I want the user to enter the password. I'm new to Spring and have been battling with this problem here (http://www.strandz.org/mvnforum/mvnf...read?thread=28). Basically the point that I've reached is needing to code the bean definition file directly - that way the password can be set at runtime. Is there any other way? This is where I am trying to replicate the bean as code:

    Code:
        public void invoke()
        {
            HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean();
            properties = PropertyUtils.getProperties( PROPS);
            String serverName = PropertyUtils.getProperty( "serverName", properties);
            String httpPort = PropertyUtils.getProperty( "httpPort", properties);
            String contextPath = PropertyUtils.getProperty( "contextPath", properties);
            proxy.setServiceUrl( "http://" + serverName + ":" + httpPort + contextPath + "/httpinvoker/rosterServiceSecure");
            proxy.setServiceInterface( example.spring.RosterService.class);
            HttpInvokerRequestExecutor httpInvokerRequestExecutor = obtainHttpInvokerRequestExecutor();
            proxy.setHttpInvokerRequestExecutor( httpInvokerRequestExecutor);
            //What to do now? When everything was in the bean I could just:
            //RosterService rosterService = (RosterService)beanFactory.getBean( "rosterServiceSecure");
            //String roster = rosterService.getRoster( MonthInYear.JULY, 2006);
            //But there is no beanFactory, just an object graph of what is in a bean
        }
    
        private HttpInvokerRequestExecutor obtainHttpInvokerRequestExecutor()
        {
            CommonsHttpInvokerRequestExecutor result = new CommonsHttpInvokerRequestExecutor();
            result.setHttpClient( obtainHttpClient());
            return result;
        }
    
        private HttpClient obtainHttpClient()
        {
            HttpClient result = null;
            HttpClientFactoryBean resultBean = new HttpClientFactoryBean();
            resultBean.setUsername( PropertyUtils.getProperty( "userName", properties));
            resultBean.setPassword( PropertyUtils.getProperty( "password", properties));
            try
            {
                result = (HttpClient)resultBean.getObject();
            }
            catch(Exception e)
            {
                Err.error( e);
            }
            return result;
        }
    I find myself wishing that as well as there being a PropertiesBeanDefinitionReader and an XmlBeanDefinitionReader, there was also an ObjectGraphDefinitionReader. I would like to be able to construct the beanFactory like this:

    Code:
            ListableBeanFactory beanFactory = new ObjectGraphApplicationContext( proxy);
    I imagine that this all seems like a bit of a descent into madness from a Spring user's point of view, which is why I'm here. Am I right in thinking that there is no way to dynamically 'get at' the bean before it starts to realise itself? Another way of putting this: "Am I right in thinking that Spring is only to be used for design-time configuration"? How should I really be going about solving this problem?

    Any help appreciated - Chris Murphy

  2. #2
    Join Date
    Aug 2004
    Posts
    2,715

    Default

    One approach for combining Spring's configuration with the possibility for providing runtime parameters I proposed here. Maybe it might be useful for you.

    Regards,
    Andreas

  3. #3
    Join Date
    Jul 2006
    Posts
    17

    Default

    Thanks Andreas,
    I didn't use your suggestion as I wanted to get back on the straight and narrow, and thought that Acegi might be able to help here, and it did. After lots of reading around I deployed acegi-security-sample-contacts-filter.war (see http://acegisecurity.org/docbook/ace...ontacts-sample) and got the non-web client sample.contact.ClientApplication.java going. For this client I grabbed the latest nightly SVN snapshot from http://acegisecurity.sourceforge.net/nightly/ (which you get to from http://acegisecurity.org/downloads.html). The secret is all in the AuthenticationSimpleHttpInvokerRequestExecutor. I didn't need to make any alterations on the server side, and the client code and bean file are quite small, so here they are:
    Code:
    package example.spring;
    
    import org.acegisecurity.Authentication;
    import org.acegisecurity.context.SecurityContextHolder;
    import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
    import org.springframework.beans.factory.ListableBeanFactory;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    import org.strandz.data.wombatrescue.objects.MonthInYear;
    import org.strandz.lgpl.util.Err;
    
    public class ScratchRosterClient
    {
        private static final String CLIENT_CONTEXT_CONFIG_LOCATION = "clientContext.xml";
    
        private final ListableBeanFactory beanFactory;
    
        public ScratchRosterClient(ListableBeanFactory beanFactory)
        {
            this.beanFactory = beanFactory;
        }
    
        public void invoke(Authentication authentication)
        {
            RosterService rosterService = (RosterService)beanFactory.getBean( "rosterServiceSecure");
            SecurityContextHolder.getContext().setAuthentication(authentication);
            String roster = rosterService.getRoster( MonthInYear.JULY, 2006);
            Err.pr( "Roster: " + roster);
            SecurityContextHolder.clearContext();
        }
    
        public static void main(String[] args)
        {
            ListableBeanFactory beanFactory = new FileSystemXmlApplicationContext(ScratchRosterClient.CLIENT_CONTEXT_CONFIG_LOCATION);
            ScratchRosterClient client = new ScratchRosterClient(beanFactory);
            String username = "tomcat";
            String password = "tomcat";
            client.invoke(new UsernamePasswordAuthenticationToken(username, password));
        }
    }
    Code:
    <beans>
    
      <!-- Resolves ${...} placeholders from client.properties -->
      <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location"><value>client.properties</value></property>
      </bean>
          
      <bean id="rosterServiceSecure" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        <property name="serviceUrl">
          <value>http://${serverName}:${httpPort}${contextPath}/httpinvoker/rosterServiceSecure</value>
        </property>
        <property name="serviceInterface">
          <value>example.spring.RosterService</value>
        </property>
        <property name="httpInvokerRequestExecutor">
          <ref local="httpInvokerRequestExecutor"/>
        </property>
      </bean>
        
      <!-- Automatically propagates ContextHolder-managed Authentication principal
           and credentials to a HTTP invoker BASIC authentication header -->
      <bean id="httpInvokerRequestExecutor" class="org.acegisecurity.context.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor"/>
     
    </beans>
    POSTSCRIPT
    A full tutorial for rich client users is available here http://www.strandz.org/spring.html
    Last edited by cjmurphy; Jan 4th, 2007 at 06:48 PM.

Posting Permissions

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