Announcement Announcement Module
Collapse
No announcement yet.
Subverting DI so a password can be entered by the user Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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

    Comment


    • #3
      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, 06:48 PM.

      Comment

      Working...
      X