diff --git a/pom.xml b/pom.xml index e2c95a50716587915d212725b940f8b322c7e586..9c611bfccf3a7eb3ed60bd343d9b6439672a32ba 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,51 @@ <version>1.7.2</version> <type>war</type> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-web</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-cas-client</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-config</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-openid</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.social</groupId> + <artifactId>spring-social-facebook</artifactId> + <version>1.0.1.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.social</groupId> + <artifactId>spring-social-twitter</artifactId> + <version>1.0.2.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + <version>3.0.7.RELEASE</version> + </dependency> + <dependency> + <groupId>jstl</groupId> + <artifactId>jstl</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>cglib</groupId> + <artifactId>cglib</artifactId> + <version>2.2.2</version> + </dependency> </dependencies> <build> <plugins> diff --git a/src/main/java/de/thm/arsnova/CasUserDetailsService.java b/src/main/java/de/thm/arsnova/CasUserDetailsService.java new file mode 100644 index 0000000000000000000000000000000000000000..b24c12152c6f770a9c513dec6b594b67ea30a219 --- /dev/null +++ b/src/main/java/de/thm/arsnova/CasUserDetailsService.java @@ -0,0 +1,26 @@ +package de.thm.arsnova; + +import java.util.ArrayList; +import java.util.List; + +import org.jasig.cas.client.validation.Assertion; +import org.springframework.security.cas.userdetails.AbstractCasAssertionUserDetailsService; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.GrantedAuthorityImpl; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +@Service +public class CasUserDetailsService extends AbstractCasAssertionUserDetailsService { + + @Override + protected UserDetails loadUserDetails(Assertion assertion) { + final List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(); + grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER")); + + System.out.println(assertion.getPrincipal().getName()); + + return new User(assertion.getPrincipal().getName(), "", true, true, true, true, grantedAuthorities); + } +} diff --git a/src/main/java/de/thm/arsnova/LoginController.java b/src/main/java/de/thm/arsnova/LoginController.java new file mode 100644 index 0000000000000000000000000000000000000000..79dc64a97a5d4ffd678faec9d97201cebce2e892 --- /dev/null +++ b/src/main/java/de/thm/arsnova/LoginController.java @@ -0,0 +1,44 @@ +package de.thm.arsnova; + +import org.springframework.security.authentication.encoding.ShaPasswordEncoder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class LoginController { + + @RequestMapping(method = RequestMethod.GET, value = "/doCasLogin") + public ModelAndView doCasLogin() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + User user = (User) authentication.getPrincipal(); + return new ModelAndView("redirect:/#auth/checkCasLogin/" + user.getUsername()); + } + + @RequestMapping(method = RequestMethod.GET, value = "/openIdLogin") + public ModelAndView openIdLogin() { + return new ModelAndView("openidlogin"); + } + + @RequestMapping(method = RequestMethod.GET, value = "/doOpenIdLogin") + public ModelAndView doOpenIdLogin() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + User user = (User) authentication.getPrincipal(); + String userHash = new ShaPasswordEncoder(256).encodePassword(user.getUsername(), ""); + return new ModelAndView("redirect:/#auth/checkCasLogin/" + userHash); + } + + @RequestMapping(method = RequestMethod.GET, value = "/doFacebookLogin") + public ModelAndView doFacebookLogin() { + return new ModelAndView("redirect:/#auth/checkCasLogin/"); + } + + @RequestMapping(method = RequestMethod.GET, value = "/doTwitterLogin") + public ModelAndView doTwitterLogin() { + return new ModelAndView("redirect:/#auth/checkCasLogin/"); + } +} diff --git a/src/main/java/de/thm/arsnova/OpenidUserDetailsService.java b/src/main/java/de/thm/arsnova/OpenidUserDetailsService.java new file mode 100644 index 0000000000000000000000000000000000000000..7d4ea974929e787c0c6833981742f05d15812dd1 --- /dev/null +++ b/src/main/java/de/thm/arsnova/OpenidUserDetailsService.java @@ -0,0 +1,24 @@ +package de.thm.arsnova; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.GrantedAuthorityImpl; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +@Service +public class OpenidUserDetailsService implements UserDetailsService { + + public UserDetails loadUserByUsername(String openIdIdentifier) { + final List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(); + grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER")); + + System.out.println(openIdIdentifier); + + return new User(openIdIdentifier, "", true, true, true, true, grantedAuthorities); + } +} \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/arsnova-servlet.xml b/src/main/webapp/WEB-INF/arsnova-servlet.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ed4eaac5cf7844bb94be2059d9a0d66cddd8bd6 --- /dev/null +++ b/src/main/webapp/WEB-INF/arsnova-servlet.xml @@ -0,0 +1,27 @@ +<?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:context="http://www.springframework.org/schema/context" + xmlns:security="http://www.springframework.org/schema/security" + xmlns:mvc="http://www.springframework.org/schema/mvc" + xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd + http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.4.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:component-scan base-package="de.thm.arsnova" /> + <context:annotation-config /> + + <mvc:resources mapping="/**.html" location="/" /> + <mvc:resources mapping="/**.png" location="/"/> + + <mvc:annotation-driven /> + + <bean id="viewResolver" + class="org.springframework.web.servlet.view.InternalResourceViewResolver"> + <property name="viewClass" + value="org.springframework.web.servlet.view.JstlView" /> + <property name="prefix" value="/WEB-INF/views/" /> + <property name="suffix" value=".jsp" /> + </bean> + +</beans> diff --git a/src/main/webapp/WEB-INF/spring/spring-main.xml b/src/main/webapp/WEB-INF/spring/spring-main.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b191bf95abc8fea87d60f7f5a1a1d700dad83bf --- /dev/null +++ b/src/main/webapp/WEB-INF/spring/spring-main.xml @@ -0,0 +1,25 @@ +<?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:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:component-scan base-package="de.thm.arsnova" /> + <context:annotation-config /> + + <bean id="connectionFactoryLocator" + class="org.springframework.social.connect.support.ConnectionFactoryRegistry"> + <property name="connectionFactories"> + <list> + <bean + class="org.springframework.social.facebook.connect.FacebookConnectionFactory"> + <!-- constructor-arg value="${facebook.clientId}" /> + <constructor-arg value="${facebook.clientSecret}" /--> + <constructor-arg value="clientId" /> + <constructor-arg value="clientSecret" /> + </bean> + </list> + </property> + </bean> + +</beans> diff --git a/src/main/webapp/WEB-INF/spring/spring-security.xml b/src/main/webapp/WEB-INF/spring/spring-security.xml new file mode 100644 index 0000000000000000000000000000000000000000..de7e3969602816d964e9b941d8fd07c6515d5db9 --- /dev/null +++ b/src/main/webapp/WEB-INF/spring/spring-security.xml @@ -0,0 +1,54 @@ +<?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:sec="http://www.springframework.org/schema/security" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:p="http://www.springframework.org/schema/p" + xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:component-scan base-package="de.thm.arsnova" /> + <context:annotation-config /> + + <sec:http entry-point-ref="casEntryPoint" disable-url-rewriting="true"> + <sec:intercept-url pattern="/j_spring_security_check" access="IS_AUTHENTICATED_ANONYMOUSLY" /> + <sec:intercept-url pattern="/doCasLogin" access="ROLE_USER" /> + <sec:custom-filter ref="casFilter" position="CAS_FILTER" /> + <sec:openid-login user-service-ref="openidUserDetailsService" default-target-url="http://localhost:8080/arsnova/doOpenIdLogin" /> + </sec:http> + + <bean id="casFilter" + class="org.springframework.security.cas.web.CasAuthenticationFilter"> + <property name="authenticationManager" ref="casAuthManager" /> + </bean> + + <bean id="casEntryPoint" + class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> + <property name="loginUrl" value="https://cas.thm.de/cas/login" /> + <property name="serviceProperties" ref="serviceProperties" /> + </bean> + + <sec:authentication-manager alias="casAuthManager"> + <sec:authentication-provider ref="casAuthProvider" /> + </sec:authentication-manager> + + <!-- TODO: Replace local URL with real world url / parameter? --> + <bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> + <property name="service" value="http://localhost:8080/arsnova/j_spring_cas_security_check" /> + <property name="sendRenew" value="false" /> + </bean> + + <bean id="casAuthProvider" + class="org.springframework.security.cas.authentication.CasAuthenticationProvider" + p:serviceProperties-ref="serviceProperties" p:key="casAuthProviderKey"> + <property name="authenticationUserDetailsService"> + <bean class="de.thm.arsnova.CasUserDetailsService" /> + </property> + <property name="ticketValidator"> + <bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"> + <constructor-arg value="https://cas.thm.de/cas" /> + </bean> + </property> + </bean> +</beans> diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 43ed129225b75623a4b4d44d122d7a589cac5868..e2a153cff8025342fc0ac0214ccc61ed6378f24b 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -1,10 +1,40 @@ <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" - version="3.0" - xmlns="http://java.sun.com/xml/ns/javaee" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" > - <display-name> - arsnova-war - </display-name> + xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + id="WebApp_ID" version="3.0"> + <display-name> + arsnova-war + </display-name> + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value> + /WEB-INF/spring/spring-main.xml + /WEB-INF/spring/spring-security.xml + </param-value> + </context-param> + <listener> + <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> + </listener> + <servlet> + <servlet-name>arsnova</servlet-name> + <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>arsnova</servlet-name> + <url-pattern>/</url-pattern> + </servlet-mapping> + <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> + <!--dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher --> + </filter-mapping> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + </welcome-file-list> </web-app> \ No newline at end of file