Spring-Social/Twitter -- ConnectController doesn't respond to /connect?
Asked Answered
J

4

9

OK so I've been pulling my hair for ages now (at least so it seems!) trying to figure out what i'm doing wrong: I have a Java project in which I want to allow users who log in (via normal Spring-Security JDBC enabled repository) to grant access to their Twitter account to my application. I have registered an app with Twitter etc and have secret and access keys and everything else required to test, however, despite all the docco's read and all the configurations tried, even though my spring config creates a ConnectController, whenever I hit the /connect/twitter I get a 404 (not found) though there is absolutely no error generated during the context coming up in Tomcat and everything else works fine (i.e all my beans get instantianted and all the views / controllers work etc).

To my understanding -- though I do struggle with the Spring Social docco, even more so as a few of the examples shown only work on specific versions! -- simply instantiating this controller should take care of the rest -- but perhaps I'm wrong???

Here's what my config looks like -- yes it's a bit allover the place:

/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <display-name>legototies</display-name>
    <servlet>
        <servlet-name>legototies</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>legototies</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- allow robots.txt -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.txt</url-pattern>
    </servlet-mapping>

    <!-- allow favicon.ico -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.ico</url-pattern>
    </servlet-mapping>

    <!-- allow everything under /static/ -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/static/*</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml,
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

/WEB-INF/legototies-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.lt" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="1">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <bean id="tilesviewResolver" class="org.springframework.web.servlet.view.tiles2.TilesViewResolver" p:order="0"/>

    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean>

</beans>

/WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
    xmlns:twitter="http://www.springframework.org/schema/social/twitter"
    xmlns:social="http://www.springframework.org/schema/social"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
       http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
       http://www.springframework.org/schema/social/twitter http://www.springframework.org/schema/social/spring-social-twitter.xsd
       http://www.springframework.org/schema/social http://www.springframework.org/schema/social/spring-social-1.1.xsd">

    <!-- **** BEGIN: Config files **** -->
    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath*:config/*.properties</value>
            </list>
        </property>
        <property name="ignoreResourceNotFound" value="true" />
    </bean>
    <!-- **** END: Config files **** -->

    <context:component-scan base-package="com.lt" />


    <!-- **** BEGIN: Database **** -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${database.driverClassName}" />
        <property name="url" value="${database.url}" />
        <property name="username" value="${database.username}" />
        <property name="password" value="${database.password}" />
        <property name="initialSize" value="${database.initial.size}" />
        <property name="maxActive" value="${database.max.active}" />
    </bean>
    <bean id="localJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg>
            <ref bean="dataSource" />
        </constructor-arg>
    </bean>

    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
    </bean>
    <!-- **** END: Database **** -->


    <bean id="messageAssembler" class="com.lt.message.MessageAssembler" />


    <!-- **** BEGIN: Scheduler **** -->
    <!-- Tasks -->
    <bean id="createTweetsScheduler" class="com.lt.scheduller.CreateTweetsScheduler">
        <constructor-arg index="0" ref="sessionFactory" />
        <constructor-arg index="1" ref="execSendTweet" />
        <constructor-arg index="2" ref="messageAssembler" />
    </bean>
    <bean id="bookScrapingNeededTask" class="com.lt.scheduller.BooksScrapingNeededCheckTask">
        <constructor-arg index="0" ref="sessionFactory" />
        <constructor-arg index="1" ref="execPageScraping" />
        <constructor-arg index="2" value="${shefari.htmlpath}" />
    </bean>

    <!-- Schedulers -->
    <task:executor id="execPageScraping" pool-size="${page.scrape.threadpool.size}" />
    <task:executor id="execSendTweet" pool-size="${broadcastTweets.threadpool.size}" />

    <task:scheduler id="mainScheduler" pool-size="${mainScheduler.size}" />
    <task:scheduled-tasks scheduler="mainScheduler">
        <task:scheduled ref="createTweetsScheduler" method="run"
            fixed-rate="${selectTweets.period.ms}" initial-delay="${selectTweets.initial.delay.ms}" />
        <task:scheduled ref="bookScrapingNeededTask" method="run"
            fixed-rate="${page.scrape.check.period.ms}" initial-delay="${page.scrape.check.initial.delay.ms}" />
    </task:scheduled-tasks>
    <!-- **** END: Scheduler **** -->


    <bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
        factory-method="noOpText" />
    <bean id="passwordEncoder"
        class="org.springframework.security.crypto.password.NoOpPasswordEncoder"
        factory-method="getInstance" />


    <!-- **** BEGIN: twitter/social **** -->
    <social:jdbc-connection-repository />
    <twitter:config app-id="${twitter.app.consumer.key}"
        app-secret="${twitter.app.consumer.secret}" />
    <bean id="userIdSource"
        class="org.springframework.social.security.AuthenticationNameUserIdSource" />
    <bean id="connectController"
        class="org.springframework.social.connect.web.ConnectController">
        <property name="connectInterceptors">
            <list>
                <bean class="com.lt.utils.TweetAfterConnectInterceptor">
                    <constructor-arg index="0" value="${twitter.app.connect.msg}" />
                </bean>
            </list>
        </property>
        <property name="applicationUrl" value="http://localhost:8080/" />
    </bean>
    <!-- **** END: twitter/social **** -->
</beans>

/WEB-INF/spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <global-method-security secured-annotations="enabled" />

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/static/**" access="permitAll" />
        <intercept-url pattern="/home" access="permitAll" />
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
    </http>

    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"

           users-by-username-query="select username,password, enabled from users where username=?" 

           authorities-by-username-query="select u.username, ur.authority from users u, user_roles ur 
              where u.id = ur.user_id and u.username =?  " 

            />
        </authentication-provider>
    </authentication-manager>
</beans:beans>

I'm not including here /WEB-INF/tiles.xml as I don't think it's relevant -- it just defines some basic templates.

Lastly, this is the project pom.xml -- please note that I'm using the latest spring social milestone (M4):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>liviutudor</groupId>
    <artifactId>legototies</artifactId>
    <packaging>war</packaging>
    <version>1.0.0-SNAPSHOT</version>
    <name>legototies</name>
    <inceptionYear>2013</inceptionYear>
    <description>This is "lego toties"</description>
    <url>http://legototies.com</url>
    <developers>
        <developer>
            <name>Liviu Tudor</name>
            <id>liviut</id>
            <email>me at liviutudor.com</email>
        </developer>
    </developers>
    <repositories>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>Maven Repository Switchboard</name>
            <url>http://repo1.maven.org/maven2</url>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>http://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>http://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <properties>
        <project.build.jdkVersion>1.6</project.build.jdkVersion>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <hibernate.version>3.6.10.Final</hibernate.version>
        <jsoup.version>1.7.2</jsoup.version>
        <junit.version>4.10</junit.version>
        <spring.version>3.2.3.RELEASE</spring.version>
        <spring.social.version>1.1.0.M4</spring.social.version>
        <spring.security.version>3.1.4.RELEASE</spring.security.version>
        <tiles.version>2.2.2</tiles.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency> <!-- needed by spring social twitter -->
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-crypto</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <!-- Spring Social -->
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-twitter</artifactId>
            <version>${spring.social.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-web</artifactId>
            <version>${spring.social.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-security</artifactId>
            <version>${spring.social.version}</version>
        </dependency>

        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <!-- this is needed for hibernate -->
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.0.GA</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.0.5</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
        </dependency>

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>${jsoup.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-extras</artifactId>
            <version>${tiles.version}</version>
        </dependency>

        <!-- Test dependencies -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>legototies</finalName>
        <defaultGoal>install</defaultGoal>
        <resources>
            <resource>
                <filtering>false</filtering>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <filtering>false</filtering>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${project.build.jdkVersion}</source>
                    <target>${project.build.jdkVersion}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

As I said everything works just fine, however, given the above, even though there is a ConnectController defined, the /connect/twitter (or any other /connect/... URL) returns 404 not found. What am I missing?

Update: Logging segment regarding the connect controller

5148 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.connect(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
5148 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[DELETE],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.removeConnections(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
5148 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}/{providerUserId}],methods=[DELETE],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.removeConnection(java.lang.String,java.lang.String,org.springframework.web.context.request.NativeWebRequest)
5149 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String org.springframework.social.connect.web.ConnectController.connectionStatus(java.lang.String,org.springframework.web.context.request.NativeWebRequest,org.springframework.ui.Model)
5150 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String org.springframework.social.connect.web.ConnectController.connectionStatus(org.springframework.web.context.request.NativeWebRequest,org.springframework.ui.Model)
5150 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[oauth_token],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth1Callback(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
5151 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[code],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth2Callback(java.lang.String,org.springframework.web.context.request.NativeWebRequest)
5152 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/connect/{providerId}],methods=[GET],params=[error],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.view.RedirectView org.springframework.social.connect.web.ConnectController.oauth2ErrorCallback(java.lang.String,java.lang.String,java.lang.String,java.lang.String,org.springframework.web.context.request.NativeWebRequest)
Jointure answered 23/10, 2013 at 23:54 Comment(8)
BTW the value for http://localhost:8080 in the ConnectController definition is set only for the purpose of when testing locally to verify this wasn't causing any problems.Jointure
Actually I think the problem might be with the <twitter:config> element as I've just realised that /connect/ on it's own as a path works, but /connect/<service> -- e.g. /connect/twitter -- returns 404.Jointure
Just a heads-up to everyone who replied to this: thank you so much! I've been busy and unable to check this, but will spend time over the weekend and will choose a winning answer by Sunday/Monday. (I'm in California as well so PST timezone just to put it in perspective).Jointure
OK so I'm afraid I cannot award yet the award to anyone :( Happy in fact to double the bounty if possible, as long as I get this sorted. I really think now that the problem is with <twitter:config> - it seems as if the ConnectController starts but doesn't register the twitter service (and yes, the app / secret keys are valid, they work perfectly fine in a separate branch with Twitter4J library, so it's not that)! It feels as if I'm missing one tiny thing which links the controller to the twitter service...any ideas?Jointure
You are using Tiles for view resolving make sure that tiles knows which views to resolve.Sinkage
@M. Deinum, please notice that there are 2 view resolvers, weighed differently, first will be the tile resolvers then falls back onto the jsp one. The view resolving works fine for all other paths apart from the /connect/... ones so that can't be it.Jointure
I totally missed the InternalResourceViewResolver, I probably need a new set of glasses :sSinkage
Update: see my conversation here: chat.stackoverflow.com/rooms/41225/… it seems there is a problem with configuring the connectionRepository bean whereby the #{request.userPrincipal.name} throws an exception...Jointure
S
4

Your ConnectController is in the wrong configuration file. You should move it to the legototies-servlet.xml.

The used HandlerMapping implementations only detect (@)Controller beans in the local context (the one loaded by the DispatcherServlet) NOT in the parent context (loaded by the ContextLoaderListener). So your ConnectController is configured but isn't doing anything because it isn't detected.

There is also another problem with your configuration, you are loading all the beans twice. This is due to the way you have configured component scanning. In both configuration files there is a <context:component-scan base-package="com.lt" /> which basically duplicates all beans. In general you should configure the DispatcherServlet to load only @Controllers and the ContextLoaderListener to load everything BUT @Controllers.

<context:component-scan base-package="com.lt">
    <context:exclude-filter type="annotation" value="org.springframework.stereotype.Controller" />
</context:component-scan>

and for the DispatcherServlet

<context:component-scan base-package="com.lt" use-default-filters="false">
    <context:include-filter type="annotation" value="org.springframework.stereotype.Controller" />
</context:component-scan>

And at first glance you also have an error in your database configuration. You are using hibernate but have configured a DataSourceTransactionManager whereas you should configure a HibernateTransactionManager. The latter is perfectly capable of controlling plain JDBC transactions.

Sinkage answered 30/10, 2013 at 12:27 Comment(21)
just trying this out-as a heads-up, the example you gave is slightly wrong: for <context:exclude-filter> and <context:include-filter>, the attribute is not value=... but expression=...Jointure
having added the <connect:include-filter> in applicationContext.xml and the <connect:exclude-filter> in legototies-servlet.xml I still see exactly the same result - 404 everywhere! :( So that's not it :(Jointure
Also I have moved the <context:component-scan>` entirely in the legototies-servlet.xml with the very same result :(Jointure
The error is that your ConnectController is in the wrong context and not detected the other ones are suggestions to improve your context (probably should have put that in a comment). To get a feeling to what is happening enable DEBUG logging for org.springframework.web (and probably org.springframework.social) and you should get more information on what is going wrong.Sinkage
OK I guess I ought to configure extended debug logging and go through it line by line. But as a heads-up, simply declaring the connect controller in a separate file didn't make any difference. (Do I need to move everything related to twitter config in the legototies-servlet.xml too?)Jointure
Moving it to another file doesn't matter, it has to be loaded by the DispatcherServlet to be detected. As long as that isn't happening the controller is basically undetected.Sinkage
I will do once I get it it configured and starting up - currently, being in a hurry I had no logging set up so just setting up SLF5J on it.Jointure
Just got a dump of the logging -- i'm updating the main body of this.Jointure
Actually it turns out the log file is too large and can't add it to the main text :( I can't see anything in there about spring social I have to say - in particular no reference at all to Twitter! I see the connect controller is initialized and maps "stuff" correctly but I am back to my first conclusion that the twitter bit never actually works.Jointure
Crap! I can't add a few lines of logging here either :( damn!Jointure
You can put it on pastebin and post a link here. What I'm interested in is what happens when the request is handled by the DispatcherServlet, because from my point it still looks like the controller isn't called.Sinkage
By the way there is no logging when i access anything under /connect/*Jointure
There should be some logging of the DispatcherServlet receiving and processing the request. You've only added the startup log, I would be interested in seeing the log of a request comming in. The logging at least shows the the controller is detected and registered.Sinkage
I've checked and checked again, once this starts, that's all the logging i get :O accessing any url's doesn't render anything in the console... Here's my log4j.xml file : pastebin.com/xUpea0XuJointure
Then either you have a problem in your logging configuration or your DispatcherServlet is doing nothing at all..Sinkage
I hear you... if the dispatcher did nothing though how come it routes the requests for /signup, /books/ etc to the correct controller? :O Hitting those urls shown in the logs (e.g. /in/books etc) definitely ends up on the right page... though no logging is generated :OJointure
It's pretty simple :O pastebin.com/xUpea0Xu It gets passed to tomcat as -Dlog4j.configuration.file=file:/....Jointure
Well you should at least see that the DispatcherServlet is handling the request. Try enabling trace logging for org.springframework.web. But as mentioned you should already see something.Sinkage
let us continue this discussion in chatJointure
To everyone who was following this, I seem to have found the issue -- see my own answer below. I will see if I can award @M. Deinum some points though for all of his ongoing suggestions.Jointure
The more I look into this, you were right about the controller being in the wrong config file and a bunch of other things so I'm awarding you this bounty.Jointure
B
3

Here you need to override some methods from ConnectController. Here I give you some code snippet (commented) which might be useful to you. The default view for the ConnectController is /connect/{providerID}Connected - once authorized and connected & /connect/{providerID}Connect - once disconnect this is the default view. You are getting 404 Error because, you don't have connect folder and twitterConnected.jsp inside that. Just to test you create a connect folder and put 1.twitterConnected.jsp and 2.twitterConnect.jsp inside that and try connecting it before you subclass your ConnectController as shown below.

@Controller
public class CustomConnectController extends ConnectController {
    @Inject
    public CustomConnectController(
            ConnectionFactoryLocator connectionFactoryLocator,
            ConnectionRepository connectionRepository) {
        super(connectionFactoryLocator, connectionRepository);
    }
    //This connectedView will be called after user authorize twitter app.  So here you can redirect   
    //users to the page you need.
    @Override
    protected String connectedView(String providerId){
        return "redirect:/user/profile";
    }
    //This connectView will be called if user disconnect from social media.  Here you can redirect 
    //them once they got disconnected.  
    @Override
    protected String connectView(String providerId) {
        return "redirect:/connect";
    }
}

Just try it and let me know your output.

Bunton answered 31/10, 2013 at 6:16 Comment(1)
See my comments above, I DO have the 2 views you have mentioned. Nevertheless, I have commented out the original ConnectController and implemented the one you suggested. And still hitting the /connect/twitterConnect renders a 404. (the controller bean though DOES get created but doesn't seem to do anything!)Jointure
E
1

1) Goes on top of web.xml ( you want security filter to be first guy to get the request)

 <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2) you are using tiles, so you wont be using jsp view resolver. change it to

<bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.tiles2.TilesView" />
    </bean>

3)servlet name has to match your servlet config file name.

EDIT: Also proper way to load context

  <servlet>
            <servlet-name>appServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/appServlet-context.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>

change appServlet to your servlet config file.

Earthbound answered 1/11, 2013 at 18:18 Comment(5)
Could you also post your controller?Earthbound
you have tiles view resolver configured and as well as jsp view resolver. lets say you return view name("index") in your controller when request comes as connect/twitter, so one of the things happen here: it either goes and tries to find(in tiles.xml) <definition name="index" ...>, or jsp view resolver is going to append /WEB-INF/jsp/index.jsp. So for you app which one fits? Remove the other one(use only one).Earthbound
Please see my comment above, you can have 2 views resolvers, they are weighed differently so they get chained.Jointure
since you are trying to use multiple view resolvers here is the post about it #1029693Earthbound
Thank you, that looks like it's based on an older Spring library though. The p-namespace used above achieves the same: docs.spring.io/spring/docs/3.0.x/spring-framework-reference/…Jointure
J
1

OK so I got it to work though somehow still not sure as to what the issue was -- I think it's somewhere in between an issue with the "shortcut" spring tags and a misconfigured security path. So it turns out that my spring-security allowed unlogged in access to /connect/.... at which point the #{request.userPrincipal.name} didn't evaluate correctly and was throwing an exception. Being spring, without logging turned on, I never spotted it, and everything was failing quietly. Having re-configured the whole twitter/social support as follows:

    <bean id="connectionFactoryLocator"
        class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
        <property name="connectionFactories">
            <list>
                <ref bean="twitterConnectFactory" />
            </list>
        </property>
    </bean>
    <bean id="twitterConnectFactory" class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
        <constructor-arg value="${twitter.app.consumer.key}" />
        <constructor-arg value="${twitter.app.consumer.secret}" />
    </bean> 

    <bean id="usersConnectionRepository"
        class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
        <constructor-arg ref="dataSource" />
        <constructor-arg ref="connectionFactoryLocator" />
        <constructor-arg ref="textEncryptor" />
    </bean>

    <bean id="connectionRepository" factory-method="createConnectionRepository"
        factory-bean="usersConnectionRepository" scope="request">
        <constructor-arg value="#{request.userPrincipal.name}" />
        <aop:scoped-proxy proxy-target-class="false" />
    </bean>

Also the connectcontroller has been configured :

<bean id="connectController"
    class="org.springframework.social.connect.web.ConnectController">
    <constructor-arg ref="connectionFactoryLocator" />
    <constructor-arg ref="connectionRepository" />
    <property name="connectInterceptors">
        <list>
            <bean class="com.lt.utils.TweetAfterConnectInterceptor">
                <constructor-arg index="0" value="${twitter.app.connect.msg}" />
            </bean>
        </list>
    </property>
</bean>

And made the changes in my spring security to actually have the user logged in in order to access the /connect... url's, this is now working. I didn't use a custom connect controller as suggested here either, and relied on the standard one. Here's my spring-security.xml for reference as well:

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <global-method-security secured-annotations="enabled" />

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/in/**" access="hasRole('ROLE_USER')" />
        <intercept-url pattern="/connect" access="hasRole('ROLE_USER')" />
        <intercept-url pattern="/connect/**" access="hasRole('ROLE_USER')" />
        <intercept-url pattern="/*" access="permitAll" />
        <intercept-url pattern="/static/**" access="permitAll" />
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/loginfailed" access="permitAll" />


        <form-login login-page="/login" default-target-url="/" authentication-failure-url="/loginfailed" />
        <logout logout-success-url="/logout" />
    </http>

    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
                users-by-username-query="select username,password, enabled from users where username=?"
                authorities-by-username-query="select u.username, ur.authority from users u, user_roles ur 
              where u.id = ur.user_id and u.username =?" />
        </authentication-provider>
    </authentication-manager>
</beans:beans>
Jointure answered 16/11, 2013 at 2:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.