Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Upgrade to Spring 3.1

Change-Id: I1d68ef97b46f4906b43fd8748c68e12d8a1e8cc8
  • Loading branch information...
commit 92647e44a60f07c7bc0eebcaafc6945d12641fe0 1 parent c2d431a
Dave Syer dsyer authored
26 README.md
View
@@ -81,6 +81,8 @@ In CloudFoundry terms
webapp that needs single sign on and access to the `api` service on
behalf of users.
+## UAA Server
+
The authentication service is `uaa`. It's a plain Spring MVC webapp.
Deploy as normal in Tomcat or your container of choice, or execute
`mvn tomcat:run` to run it directly from `uaa` directory in the source tree.
@@ -95,16 +97,30 @@ It supports the APIs defined in the UAA-APIs document. To summarise:
3. A /check_token endpoint, to allow resource servers to obtain information about
an access token submitted by an OAuth2 client.
-4. SCIM user provisioning endpoints (todo)
+4. SCIM user provisioning endpoint
-5. OpenID connect endpoints to support authentication /userinfo and /check_id
-(todo). Implemented roughly enough to get it working (so /app authenticates
-here), but not to meet the spec.
+5. OpenID connect endpoints to support authentication /userinfo and
+/check_id (todo). Implemented roughly enough to get it working (so
+/app authenticates here), but not to meet the spec.
Authentication can be performed by command line clients by submitting
credentials directly to the `/authorize` endpoint (as described in
UAA-API doc). There is an `ImplicitAccessTokenProvider` in Spring
-Security OAuth that can do the heavy lifting.
+Security OAuth that can do the heavy lifting if your client is Java.
+
+By default `uaa` will launch with a context root `/uaa`. There is a
+Maven profile `vcap` to launch with context root `/`.
+
+### User Account Data
+
+The default is to use an in-memory, hash-based user store that is
+pre-populated with some test users: e.g. `dale` has password
+`password` and `marissa` has password `koala`.
+
+To use a RDBMS for user data activate the Spring profiles `jdbc` and
+one of `hsqldb` or `postgresql`. The `hsqldb` profile will start up
+with an in-memory RDBMS by default. Warning: the database will start
+empty, so no users can log in until the first account is created.
## The API Application
2  pom.xml
View
@@ -13,7 +13,7 @@
</modules>
<properties>
- <spring.version>3.0.6.RELEASE</spring.version>
+ <spring.version>3.1.0.RELEASE</spring.version>
<spring.security.version>3.1.0.RELEASE</spring.security.version>
<spring.security.oauth.version>1.0.0.BUILD-SNAPSHOT</spring.security.oauth.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
54 uaa/src/main/java/org/cloudfoundry/identity/uaa/config/HandlerAdapterFactoryBean.java
View
@@ -12,21 +12,29 @@
*/
package org.cloudfoundry.identity.uaa.config;
-import java.lang.reflect.Method;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
+import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.ui.ExtendedModelMap;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
+import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerAdapter;
-import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
-import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
+import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
/**
* Factory for a handler adapter that sniffs the results from {@link RequestMapping} method executions and adds an ETag
@@ -35,19 +43,24 @@
* @author Dave Syer
*
*/
-public class HandlerAdapterFactoryBean implements FactoryBean<HandlerAdapter> {
+public class HandlerAdapterFactoryBean implements FactoryBean<HandlerAdapter>, ApplicationContextAware {
+
+ private ApplicationContext applicationContext;
@Override
public HandlerAdapter getObject() throws Exception {
- AnnotationMethodHandlerAdapter adapter = new AnnotationMethodHandlerAdapter();
+ RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
+ adapter.setApplicationContext(applicationContext);
adapter.setMessageConverters(getMessageConverters());
adapter.setOrder(0);
- adapter.setCustomModelAndViewResolver(new ScimEtagModelAndViewResolver());
+ adapter.setReturnValueHandlers(Arrays
+ .<HandlerMethodReturnValueHandler> asList(new ScimEtagHandlerMethodReturnValueHandler(getMessageConverters())));
+ adapter.afterPropertiesSet();
return adapter;
}
- private HttpMessageConverter<?>[] getMessageConverters() {
- return new RestTemplate().getMessageConverters().toArray(new HttpMessageConverter[0]);
+ private List<HttpMessageConverter<?>> getMessageConverters() {
+ return new RestTemplate().getMessageConverters();
}
@Override
@@ -60,17 +73,32 @@ public boolean isSingleton() {
return true;
}
- private static class ScimEtagModelAndViewResolver implements ModelAndViewResolver {
+ private static class ScimEtagHandlerMethodReturnValueHandler extends RequestResponseBodyMethodProcessor {
+
+ public ScimEtagHandlerMethodReturnValueHandler(List<HttpMessageConverter<?>> messageConverters) {
+ super(messageConverters);
+ }
@Override
- public ModelAndView resolveModelAndView(Method handlerMethod, @SuppressWarnings("rawtypes") Class handlerType,
- Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) {
+ public boolean supportsReturnType(MethodParameter returnType) {
+ return ScimUser.class.isAssignableFrom(returnType.getMethod().getReturnType());
+ }
+
+ @Override
+ public void handleReturnValue(Object returnValue, MethodParameter returnType,
+ ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException,
+ HttpMediaTypeNotAcceptableException {
if (returnValue instanceof ScimUser) {
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
response.addHeader("ETag", "\"" + ((ScimUser) returnValue).getVersion() + "\"");
}
- return ModelAndViewResolver.UNRESOLVED;
+ super.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
}
2  uaa/src/main/java/org/cloudfoundry/identity/uaa/oauth/AccessController.java
View
@@ -31,7 +31,7 @@ public String getIdentity(HttpSession session) {
}
@RequestMapping("/oauth/confirm_access")
- public String confirm(UnconfirmedAuthorizationCodeClientToken clientAuth, Map<String, Object> model, final HttpServletRequest request)
+ public String confirm(@ModelAttribute UnconfirmedAuthorizationCodeClientToken clientAuth, Map<String, Object> model, final HttpServletRequest request)
throws Exception {
if (clientAuth == null) {
26 uaa/src/main/webapp/WEB-INF/spring-data-source.xml
View
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
- xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+ xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:property-placeholder properties-ref="applicationProperties" />
@@ -14,13 +14,13 @@
<property name="resource" value="classpath:/uaa.yml" />
<property name="keyReplacements">
<map>
- <entry key="databases.#{systemProperties['PLATFORM']?:'hsqldb'}" value="database" />
+ <entry key="databases.#{@platform}" value="database" />
</map>
</property>
</bean>
<bean class="org.cloudfoundry.identity.uaa.config.YamlPropertiesFactoryBean">
<property name="resource" value="${CLOUD_FOUNDRY_CONFIG_PATH:config}/uaa.yml" />
- <property name="ignoreResourceNotFound" value="true"/>
+ <property name="ignoreResourceNotFound" value="true" />
</bean>
</list>
</property>
@@ -32,9 +32,21 @@
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
-
+
<jdbc:initialize-database ignore-failures="ALL">
- <jdbc:script location="classpath:org/cloudfoundry/identity/uaa/scim/schema-${PLATFORM:hsqldb}.sql"/>
+ <jdbc:script location="classpath:org/cloudfoundry/identity/uaa/scim/schema-#{@platform}.sql" />
</jdbc:initialize-database>
+ <beans profile="default,hsqldb">
+ <bean id="platform" class="java.lang.String">
+ <constructor-arg value="hsqldb" />
+ </bean>
+ </beans>
+
+ <beans profile="postgresql">
+ <bean id="platform" class="java.lang.String">
+ <constructor-arg value="postgresql" />
+ </bean>
+ </beans>
+
</beans>
70 uaa/src/main/webapp/WEB-INF/spring-servlet.xml
View
@@ -3,12 +3,10 @@
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
+ http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
- <import resource="spring-data-source.xml"/>
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<sec:debug />
@@ -101,26 +99,6 @@
<constructor-arg ref="userDatabase" />
</bean>
- <bean id="userDatabase" class="org.cloudfoundry.identity.uaa.user.InMemoryUaaUserDatabase">
- <constructor-arg ref="userData" />
- </bean>
-
- <bean id="scimUserProvisioning" class="org.cloudfoundry.identity.uaa.scim.InMemoryScimUserProvisioning">
- <constructor-arg ref="userData" />
- </bean>
-
- <bean id="userData" class="org.cloudfoundry.identity.uaa.config.UaaUserMapFactoryBean">
- <constructor-arg>
- <list value-type="org.cloudfoundry.identity.uaa.user.UaaUser">
- <value>dale|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|olds@vmware.com|Dale|Olds</value>
- <value>joel|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|jdsa@vmware.com|Joel|D'Sa</value>
- <value>dave|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|dsyer@vmware.com|Dave|Syer</value>
- <value>luke|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|ltaylor@vmware.com|Luke|Taylor</value>
- <value>marissa|$2a$10$ikFXo9IFG6zbMbhGcssySOhjDsGPpqzKwsdVOeCvJ7JoWjSQxyfs6|marissa@test.org|Marissa|Bloggs</value>
- </list>
- </constructor-arg>
- </bean>
-
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.RandomValueTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
@@ -213,4 +191,46 @@
<bean id="homeController" class="org.cloudfoundry.identity.uaa.home.HomeController" />
+ <beans profile="default,dev">
+
+ <bean id="userDatabase" class="org.cloudfoundry.identity.uaa.user.InMemoryUaaUserDatabase">
+ <constructor-arg ref="userData" />
+ </bean>
+
+ <bean id="scimUserProvisioning" class="org.cloudfoundry.identity.uaa.scim.InMemoryScimUserProvisioning">
+ <constructor-arg ref="userData" />
+ </bean>
+
+ <bean id="userData" class="org.cloudfoundry.identity.uaa.config.UaaUserMapFactoryBean">
+ <constructor-arg>
+ <list value-type="org.cloudfoundry.identity.uaa.user.UaaUser">
+ <value>dale|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|olds@vmware.com|Dale|Olds</value>
+ <value>joel|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|jdsa@vmware.com|Joel|D'Sa</value>
+ <value>dave|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|dsyer@vmware.com|Dave|Syer</value>
+ <value>luke|$2a$10$HoWPAUn9zqmmb0b.2TBZWe6cjQcxyo8TDwTX.5G46PBL347N3/0zO|ltaylor@vmware.com|Luke|Taylor</value>
+ <value>marissa|$2a$10$ikFXo9IFG6zbMbhGcssySOhjDsGPpqzKwsdVOeCvJ7JoWjSQxyfs6|marissa@test.org|Marissa|Bloggs</value>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ </beans>
+
+ <beans profile="jdbc">
+
+ <import resource="spring-data-source.xml" />
+
+ <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
+ <property name="dataSource" ref="dataSource" />
+ </bean>
+
+ <bean id="userDatabase" class="org.cloudfoundry.identity.uaa.user.JdbcUaaUserDatabase">
+ <constructor-arg ref="jdbcTemplate" />
+ </bean>
+
+ <bean id="scimUserProvisioning" class="org.cloudfoundry.identity.uaa.scim.JdbcScimUserProvisioning">
+ <constructor-arg ref="jdbcTemplate" />
+ </bean>
+
+ </beans>
+
</beans>
22 uaa/src/test/java/org/cloudfoundry/identity/uaa/BootstrapTests.java
View
@@ -13,6 +13,11 @@
package org.cloudfoundry.identity.uaa;
+import static org.junit.Assert.assertNotNull;
+
+import org.cloudfoundry.identity.uaa.user.InMemoryUaaUserDatabase;
+import org.cloudfoundry.identity.uaa.user.JdbcUaaUserDatabase;
+import org.junit.After;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
@@ -22,10 +27,25 @@
*
*/
public class BootstrapTests {
+
+
+ @After
+ public void cleanup() {
+ System.clearProperty("spring.profiles.active");
+ }
+
+ @Test
+ public void testRootContextWithJdbcUsers() throws Exception {
+ System.setProperty("spring.profiles.active", "jdbc,hsqldb");
+ GenericXmlApplicationContext context = new GenericXmlApplicationContext(new FileSystemResource("src/main/webapp/WEB-INF/spring-servlet.xml"));
+ assertNotNull(context.getBean("userDatabase", JdbcUaaUserDatabase.class));
+ context.close();
+ }
@Test
- public void testRootContext() throws Exception {
+ public void testRootContextWithDevUsers() throws Exception {
GenericXmlApplicationContext context = new GenericXmlApplicationContext(new FileSystemResource("src/main/webapp/WEB-INF/spring-servlet.xml"));
+ assertNotNull(context.getBean("userDatabase", InMemoryUaaUserDatabase.class));
context.close();
}
Please sign in to comment.
Something went wrong with that request. Please try again.