Announcement Announcement Module
Collapse
No announcement yet.
Custom authorization - 0.8.2 to 0.9 upgrade woes Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Custom authorization - 0.8.2 to 0.9 upgrade woes

    Hi

    We have a Spring application that uses customised authorization to integrate with our corporate user database using acegi 0.8.2.

    Here's the changed config:

    <bean id="regAuthenticationDAO" class="uk.co.anm.london.security.RegJdbcDaoImpl">
    <property name="dataSource">
    <ref bean="regSource"/>
    </property>
    <property name="usersByUsernameMapping">
    <ref bean="usersByUsernameMapping"/>
    </property>
    <property name="authoritiesByUsernameMapping">
    <ref bean="authoritiesByUsernameMapping"/>
    </property>
    </bean>

    <!-- New bean(s) to override Acegi queries -->
    <bean id="usersByUsernameMapping" class="uk.co.anm.london.security.mapping.UserByUse rnameMapping">
    <property name="dataSource">
    <ref bean="regSource" />
    </property>
    <property name="sql">
    <value>SELECT userid, email as username,password,'true' as enabled FROM users WHERE email = ? and valid='Y'</value>
    </property>
    </bean>

    <bean id="authoritiesByUsernameMapping" class="uk.co.anm.london.security.mapping.Authoriti esByUsernameMapping">
    <property name="dataSource">
    <ref bean="regSource" />
    </property>
    <property name="sql">
    <value>SELECT email as username, 'REGISTERED_USER' as authority FROM users WHERE email = ? and valid='Y'</value>
    </property>
    </bean>



    <bean id="registrationAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthe nticationProvider">
    <property name="authenticationDao"><ref local="regAuthenticationDAO"/></property>
    <property name="userCache"><ref local="acegiUserCache"/></property>
    </bean>

    <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderMana ger">
    <property name="providers">
    <list>
    <ref local="registrationAuthenticationProvider"/>
    <ref local="rememberMeAuthenticationProvider"/>
    </list>
    </property>
    </bean>

    This has been working fine but what we now need to do is to chain another authentication provider. I've read that 0.8.* doesn't do this very elegantly but 0.9 does. So off I go and download the 0.9 jar and find that the getters and setters for both usersByUsernameMapping and authoritiesByUsernameMapping have been refactored out and that the MappingSqlQuery inner classes are now private.

    I have 2 questions:

    1. How do I now customize the queries?

    2. Why!?!? This really irritating as I've already had to change all this once before when upgrading to 0.8 in the first place. I've also seen that all the packages have changed in 1.0. Should we go straight to that and avoid yet more refactoring hassle.

    Many thanks

    Charlie

  • #2
    Go for the latest version, think its 1.0.3! If all you want to do is use custom queries, you can just inject these into the JdbcDaoImpl you don't need a subclass.

    Comment


    • #3
      Blimey that was quick - Thanks but there is something I forgot to add.

      I subclassed UserByUsernameMapping so it could return a custom user object because we use an extra id to track and record user activity on the site. Here's the code FYI.


      package uk.co.anm.london.security;

      import net.sf.acegisecurity.GrantedAuthority;
      import net.sf.acegisecurity.GrantedAuthorityImpl;

      @SuppressWarnings("serial")
      public class RegUser extends net.sf.acegisecurity.providers.dao.User{

      private Long id;

      public RegUser() {
      super();
      }

      public RegUser(Long userId, String userName, String password) throws IllegalArgumentException {
      super(userName, password, true, true, true, true, new GrantedAuthority[]{new GrantedAuthorityImpl("HOLDER")});
      this.id = userId;
      }

      public RegUser(Long userId, String userName, String password, GrantedAuthority[] authorities ) throws IllegalArgumentException {
      super(userName, password, true, true, true, true, authorities);
      this.id = userId;
      }

      public Long getId() {
      return id;
      }

      public void setId(Long id) {
      this.id = id;
      }


      }


      package uk.co.anm.london.security.mapping;

      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.sql.Types;

      import javax.sql.DataSource;

      import org.springframework.jdbc.core.SqlParameter;
      import org.springframework.jdbc.object.MappingSqlQuery;

      import uk.co.anm.london.security.RegUser;

      public class UserByUsernameMapping extends MappingSqlQuery {

      public UserByUsernameMapping() {
      super();
      // TODO Auto-generated constructor stub
      }

      public UserByUsernameMapping(DataSource arg0, String arg1) {
      super(arg0, arg1);
      // TODO Auto-generated constructor stub
      }

      @Override
      public void setSql(String sql) {
      super.setSql(sql);
      declareParameter(new SqlParameter(Types.VARCHAR));
      compile();
      }

      @Override
      protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
      Long id = rs.getLong(1);
      String username = rs.getString(2);
      String password = rs.getString(3);

      RegUser ret = new RegUser(id, username, password);
      return ret;
      }
      }

      So I need to get round this as well.
      If anyone can help it will make my day.

      cheers

      Charlie

      Comment


      • #4
        In that case just carry on extending JdbcDaoImpl but override initMappingSqlQueries. You can then get it to use your mappings instead.

        This is was the JdbcDaoImpl does, just create your mappings instead.
        Code:
            protected void initMappingSqlQueries() {
                this.usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());
                this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
            }
        As for the net.sf to org.acegisecurity change, it's always a pain when this happens but such is life for these things. Early adoption and all that. Hibernate did the same thing from 2 to 3 (I think it was those versions anway).

        Comment


        • #5
          Brilliant - Thanks, Looks like a goer as the SQLMapping queries are now protected in 1.0.3 and not private as v 0.9.

          It is still a bit baffling that they were private with getters and setters in v 0.8, private without them and then protected in v1.*. I take your point about early adopters though - Them's the risks I guess. I'll post back if it works.

          Many many thanks

          Charlie

          Comment


          • #6
            After a brief but bloody struggle with the new configuration all is working perfectly.

            Thanks for your suggestions.

            If anyone wants the source code and configs just send me a private message.

            Hooray!

            Comment


            • #7
              Glad you got it all working! I do know what you mean with; you can inject them, the methods private, the methods protected. I would have thought injection really would make more sense, thats what Spring is all about!

              Comment


              • #8
                Originally posted by zebthecat View Post
                After a brief but bloody struggle with the new configuration all is working perfectly.

                Thanks for your suggestions.

                If anyone wants the source code and configs just send me a private message.

                Hooray!
                Hi,
                Could you please provide me with the source code and config files because I have given up to get it to work. I tried with the latest version( 1.0.3 ) but if your config is for 0.8.2 then I will degrade to that version.
                Many thanks in advance.

                Comment


                • #9
                  The main thing here is the package name changes. If you have some specific problems, I might be able to help.

                  Comment


                  • #10
                    Originally posted by karldmoore View Post
                    The main thing here is the package name changes. If you have some specific problems, I might be able to help.
                    my config looks like this. Please suggest me what I am doing wrong

                    <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoI mpl">
                    <property name="dataSource"><ref bean="dataSource"/></property>
                    <property name="usersByUsernameMapping">
                    <ref bean="customUsersByUsernameMapping"/>
                    </property>
                    </bean>

                    <bean id="customUsersByUsernameMapping" class="no.ya.vertigo.dao.impl.springjdbc.UserByUse rnameMapping">
                    <property name="dataSource">
                    <ref bean="dataSource" />
                    </property>
                    <property name="sql">
                    <value>SELECT LoginName, UserPassword, Email, FirstName, LastName FROM Users WHERE LoginName=?</value>
                    </property>
                    </bean>

                    and UserByUsernameMapping.java is as follows:

                    package no.ya.vertigo.dao.impl.springjdbc;

                    import java.sql.ResultSet;
                    import java.sql.SQLException;
                    import java.sql.Types;

                    import javax.sql.DataSource;

                    import no.ya.vertigo.domain.LoggedInMemberData;

                    import org.springframework.jdbc.core.SqlParameter;
                    import org.springframework.jdbc.object.MappingSqlQuery;

                    public class UserByUsernameMapping extends MappingSqlQuery {

                    private static org.apache.log4j.Logger log = org.apache.log4j.Logger
                    .getLogger(UserByUsernameMapping.class);

                    public UserByUsernameMapping() {
                    super();
                    log.debug("UserByUsernameMapping()");
                    }

                    public UserByUsernameMapping(DataSource dataSource, String sql) {
                    super(dataSource, sql);
                    log.debug("UserByUsernameMapping(DataSource dataSource, String sql)");
                    }

                    @Override
                    public void setSql(String sql) {
                    log.debug("entering setSql()");
                    super.setSql(sql);
                    declareParameter(new SqlParameter(Types.VARCHAR));
                    compile();
                    }

                    @Override
                    protected Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                    log.debug("entering mapRow()");
                    String loginName = rs.getString(1);
                    String userPassword = rs.getString(2);
                    String email = rs.getString(3);
                    String firstName = rs.getString(4);
                    String lastName = rs.getString(5);

                    LoggedInMemberData ret = new LoggedInMemberData(loginName,
                    userPassword, email, firstName, lastName);

                    log.debug("LoggedInMemberData " + ret.toString());
                    return ret;
                    }
                    }

                    here is the stack trace
                    org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'jdbcDaoImpl' defined in ServletContext resource [/WEB-INF/applicationContext-acegi-security.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyExcep tion: Invalid property 'usersByUsernameMapping' of bean class [org.acegisecurity.userdetails.jdbc.JdbcDaoImpl]: Bean property 'usersByUsernameMapping' is not writable or has an invalid setter method: Does the parameter type of the setter match the return type of the getter?
                    org.springframework.beans.NotWritablePropertyExcep tion: Invalid property 'usersByUsernameMapping' of bean class [org.acegisecurity.userdetails.jdbc.JdbcDaoImpl]: Bean property 'usersByUsernameMapping' is not writable or has an invalid setter method: Does the parameter type of the setter match the return type of the getter?
                    at org.springframework.beans.BeanWrapperImpl.setPrope rtyValue(BeanWrapperImpl.java:831)
                    at org.springframework.beans.BeanWrapperImpl.setPrope rtyValue(BeanWrapperImpl.java:733)

                    at

                    Comment


                    • #11
                      If you put your code in [ code] [ /code] tags, it's sooooo much easier to read. You now need to extend JdbcDaoImpl and override the initMappingSqlQueries method.

                      Code:
                          /**
                           * Extension point to allow other MappingSqlQuery objects to be substituted in a subclass
                           */
                          protected void initMappingSqlQueries() {
                              this.usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());
                              this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
                          }

                      Comment


                      • #12
                        Originally posted by karldmoore View Post
                        If you put your code in [ code] [ /code] tags, it's sooooo much easier to read. You now need to extend JdbcDaoImpl and override the initMappingSqlQueries method.

                        Code:
                            /**
                             * Extension point to allow other MappingSqlQuery objects to be substituted in a subclass
                             */
                            protected void initMappingSqlQueries() {
                                this.usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());
                                this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
                            }
                        Now I am one step ahead, everything is working fine now except one thing that is when I log in with correct username and password I get the following error message:

                        Code:
                         
                        Reason: SQL 'SELECT LoginName, UserPassword, Email, FirstName, LastName FROM Users WHERE LoginName=?' requires 1 bind variables, but 0 variables were declared for this object; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: SQL 'SELECT LoginName, UserPassword, Email, FirstName, LastName FROM Users WHERE LoginName=?' requires 1 bind variables, but 0 variables were declared for this object

                        Comment


                        • #13
                          There must be a problem with the query class. Is it possible to have a look at it?

                          Comment


                          • #14
                            Originally posted by karldmoore View Post
                            There must be a problem with the query class. Is it possible to have a look at it?
                            Now I have found out what the problem was, I left out following lines from the constructor

                            declareParameter(new SqlParameter(Types.VARCHAR));
                            compile();

                            Thank you very very much for your help, I really appreciate it.

                            Comment


                            • #15
                              Not a problem, glad it's all working! By the sounds of it, apart from the JdbcDaoImpl changes, it wasn't that much of a problem.

                              Comment

                              Working...
                              X