From ea0b54f73a9b358f8f0c92f4cff35f0c7bba5c2a Mon Sep 17 00:00:00 2001
From: Chris Dutra <cdutra@pivotal.io>
Date: Fri, 1 May 2015 15:56:48 -0700
Subject: [PATCH 1/9] Bump next develop version

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index d13ea101cca..544df399390 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +1 @@
-version=2.2.6
+version=2.2.7-SNAPSHOT

From fb40fe91677ee107f685214eba23c013bf23ca5e Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Tue, 5 May 2015 09:09:01 -0600
Subject: [PATCH 2/9] Upgrade to Spring Framework 4.1.x
 https://www.pivotaltracker.com/story/show/93706906 [#93706906] Spring
 Security Oauth2 suddenly disallows GET to /oauth/token New event thrown when
 basic auth failed approvals_deleted becomes additionalInformation so that the
 clientDetailsModification is simplified. Oauth show case should use same
 Spring Security Oauth 2 version as parent Bump next dev version to 2.3.0 to
 indicate minor API change Jackson 1 is no longer supported.

---
 common/build.gradle                           | 12 +--
 .../uaa/audit/event/AbstractUaaEvent.java     | 32 ++++----
 .../audit/event/ApprovalModifiedEvent.java    |  8 +-
 .../uaa/audit/event/GroupModifiedEvent.java   | 13 ++-
 .../uaa/audit/event/TokenIssuedEvent.java     | 21 ++---
 .../uaa/audit/event/UserModifiedEvent.java    |  7 +-
 .../AuthzAuthenticationFilter.java            | 12 ++-
 .../ClientParametersAuthenticationFilter.java | 13 +--
 .../login/LoginInfoEndpoint.java              |  5 +-
 .../KeystoneAuthenticationManager.java        |  2 +-
 .../identity/uaa/client/ClientConstants.java  |  1 +
 .../uaa/client/SocialClientUserDetails.java   | 12 +--
 .../identity/uaa/codestore/ExpiringCode.java  | 10 +--
 .../uaa/config/IdentityProviderBootstrap.java |  5 +-
 .../uaa/config/NestedMapPropertySource.java   | 13 ++-
 .../identity/uaa/error/UaaException.java      | 20 ++---
 .../uaa/error/UaaExceptionDeserializer.java   | 17 ++--
 .../uaa/error/UaaExceptionSerializer.java     | 16 ++--
 .../ldap/LdapIdentityProviderDefinition.java  |  2 +-
 .../identity/uaa/login/AutologinRequest.java  |  7 +-
 .../login/PasscodeAuthenticationFilter.java   | 18 ++--
 .../uaa/login/PasscodeInformation.java        | 10 +--
 .../identity/uaa/login/SamlUserAuthority.java |  6 +-
 .../saml/IdentityProviderDefinition.java      |  2 +-
 .../uaa/message/PasswordChangeRequest.java    |  4 +-
 .../uaa/oauth/CheckTokenEndpoint.java         | 13 ++-
 .../uaa/oauth/ClientAdminEndpoints.java       |  8 +-
 .../JdbcQueryableClientDetailsService.java    |  7 +-
 .../uaa/oauth/RemoteTokenServices.java        |  8 +-
 .../uaa/oauth/SecretChangeRequest.java        |  7 +-
 .../identity/uaa/oauth/approval/Approval.java | 11 +--
 .../client/ClientDetailsModification.java     | 22 ++---
 ...sitiveOAuth2SecurityExpressionMethods.java | 12 +--
 .../identity/uaa/oauth/token/OpenIdToken.java | 24 +++---
 .../uaa/oauth/token/UaaTokenServices.java     | 22 +++--
 .../web/TokenEndpointPostProcessor.java       | 44 ++++++++++
 .../identity/uaa/user/UaaAuthority.java       |  2 +-
 .../identity/uaa/util/JsonUtils.java          | 17 +++-
 .../uaa/util/json/JsonDateDeserializer.java   | 14 ++--
 .../uaa/util/json/JsonDateSerializer.java     | 12 +--
 .../identity/uaa/zone/IdentityProvider.java   |  6 +-
 .../IdentityProviderValidationRequest.java    |  6 +-
 .../identity/uaa/zone/IdentityZone.java       |  6 +-
 .../MultitenantJdbcClientDetailsService.java  | 35 ++++----
 .../config/IdentityProviderBootstrapTest.java | 62 +++++++-------
 .../uaa/oauth/ClientAdminEndpointsTests.java  | 13 +--
 .../uaa/oauth/RemoteTokenServicesTests.java   |  5 +-
 .../ClientDetailsModificationTests.java       | 47 +++++++++++
 .../oauth/token/UaaTokenServicesTests.java    | 36 ++++----
 .../identity/uaa/rest/MessageTests.java       |  8 +-
 .../identity/uaa/test/TestAccountSetup.java   |  8 +-
 gradle.properties                             |  2 +-
 .../uaa/login/AccountCreationService.java     |  2 +-
 .../login/AutologinAuthenticationManager.java | 19 ++---
 .../identity/uaa/login/DescribedApproval.java |  2 +-
 .../login/EmailAccountCreationService.java    | 11 +--
 .../uaa/login/EmailInvitationsService.java    |  8 +-
 .../uaa/login/EmailResetPasswordService.java  | 10 +--
 .../uaa/login/LoginUaaApprovalsService.java   | 20 ++---
 .../uaa/login/RestUaaApprovalsService.java    |  1 -
 .../uaa/login/UaaExpiringCodeService.java     | 26 +++---
 login/src/main/resources/login-ui.xml         |  5 +-
 .../EmailAccountCreationServiceTests.java     |  6 +-
 .../login/EmailResetPasswordServiceTests.java |  3 +-
 .../uaa/login/test/MockMvcTestClient.java     | 10 +--
 .../main/webapp/WEB-INF/spring-servlet.xml    |  8 +-
 .../main/webapp/WEB-INF/spring-servlet.xml    |  8 +-
 samples/oauth-showcase/build.gradle           |  2 +-
 .../identity/uaa/scim/ScimCore.java           |  2 +-
 .../identity/uaa/scim/ScimGroup.java          |  5 +-
 .../uaa/scim/ScimGroupExternalMember.java     |  5 +-
 .../uaa/scim/ScimGroupJsonDeserializer.java   | 14 ++--
 .../uaa/scim/ScimGroupJsonSerializer.java     | 11 +--
 .../identity/uaa/scim/ScimGroupMember.java    | 12 +--
 .../identity/uaa/scim/ScimMeta.java           |  7 +-
 .../identity/uaa/scim/ScimUser.java           | 18 ++--
 .../uaa/scim/ScimUserJsonDeserializer.java    | 17 ++--
 .../scim/endpoints/ChangeEmailEndpoints.java  | 16 ++--
 .../endpoints/PasswordResetEndpoints.java     | 10 +--
 .../uaa/scim/endpoints/PasswordScore.java     |  4 +-
 .../identity/uaa/scim/ScimUserTests.java      | 19 ++---
 .../endpoints/ChangeEmailEndpointsTest.java   |  3 +-
 .../endpoints/PasswordResetEndpointsTest.java |  3 +-
 shared_versions.gradle                        | 10 ++-
 .../WEB-INF/spring/login-server-security.xml  |  4 -
 .../webapp/WEB-INF/spring/oauth-endpoints.xml |  2 +
 .../ScimUserEndpointsIntegrationTests.java    | 10 +--
 .../integration/feature/ImplicitGrantIT.java  |  7 +-
 .../feature/OpenIdTokenGrantsIT.java          | 41 ++++------
 .../util/IntegrationTestUtils.java            |  2 +-
 .../login/AccountsControllerMockMvcTests.java |  4 +-
 .../uaa/login/PasscodeMockMvcTests.java       | 16 ++--
 .../mock/audit/AuditCheckMvcMockTests.java    | 52 ++++++------
 .../ClientAdminEndpointsMockMvcTests.java     | 13 ++-
 .../ExpiringCodeStoreMockMvcTests.java        | 24 +++---
 .../token/TokenKeyEndpointMockMvcTests.java   |  4 +-
 .../uaa/mock/token/TokenMvcMockTests.java     | 14 ++--
 .../identity/uaa/mock/util/MockMvcUtils.java  | 68 ++++++++-------
 ...IdentityProviderEndpointsMockMvcTests.java |  2 +-
 .../IdentityZoneEndpointsMockMvcTests.java    | 82 +++++++++----------
 ...dentityZoneSwitchingFilterMockMvcTest.java |  6 +-
 .../PasswordResetEndpointsMockMvcTests.java   |  6 +-
 .../ScimGroupEndpointsMockMvcTests.java       | 18 ++--
 .../ScimUserEndpointsMockMvcTests.java        | 18 ++--
 .../endpoints/ScimUserLookupMockMvcTests.java | 10 +--
 .../identity/uaa/test/TestClient.java         | 19 ++---
 106 files changed, 731 insertions(+), 713 deletions(-)
 create mode 100644 common/src/main/java/org/cloudfoundry/identity/uaa/security/web/TokenEndpointPostProcessor.java
 create mode 100644 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModificationTests.java

diff --git a/common/build.gradle b/common/build.gradle
index 80ff05ddfc4..2efeee69c54 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -1,15 +1,15 @@
 description = 'CloudFoundry Identity Common Jar'
 
 dependencies {
-  compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version:'1.47'
-  compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version:'1.47'
+  compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version:parent.bcpkixVersion
+  compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version:parent.bcpkixVersion
   compile group: 'org.springframework.security', name: 'spring-security-ldap', version:parent.springSecurityVersion
   compile group: 'org.springframework.ldap', name: 'spring-ldap-core', version:parent.springSecurityLdapVersion
   compile group: 'org.springframework.ldap', name: 'spring-ldap-core-tiger', version:parent.springSecurityLdapVersion
-  compile(group: 'org.apache.directory.api', name: 'api-ldap-model', version:'1.0.0-M22') {
+  compile(group: 'org.apache.directory.api', name: 'api-ldap-model', version:parent.apacheLdapApiVersion) {
     exclude(module: 'slf4j-api')
   }
-  compile group: 'org.springframework.security', name: 'spring-security-jwt', version:'1.0.2.RELEASE'
+  compile group: 'org.springframework.security', name: 'spring-security-jwt', version:parent.springSecurityJwtVersion
   compile(group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version:parent.springSecurityOAuthVersion) {
     exclude(module: 'commons-codec')
   }
@@ -42,7 +42,9 @@ dependencies {
   compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.7'
   compile group: 'org.hibernate', name: 'hibernate-validator', version:'4.3.1.Final'
   compile group: 'org.aspectj', name: 'aspectjrt', version:'1.6.9'
-  compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version:'1.9.2'
+  //compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version:'1.9.2'
+  compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version:parent.jacksonVersion
+  compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version:parent.jacksonVersion
   compile group: 'org.yaml', name: 'snakeyaml', version:'1.12'
   compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version:'1.1.7'
   compile group: 'com.googlecode.flyway', name: 'flyway-core', version:'2.3.1'
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java
index 512e5d8a219..fa7dacaba38 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,11 +12,9 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.audit.event;
 
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
 import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
@@ -24,9 +22,6 @@
 import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.context.ApplicationEvent;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -36,21 +31,26 @@
 import org.springframework.security.oauth2.provider.OAuth2Authentication;
 import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
 
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
 /**
  * Base class for UAA events that want to publish audit records.
- * 
+ *
  * @author Luke Taylor
  * @author Dave Syer
- * 
+ *
  */
 public abstract class AbstractUaaEvent extends ApplicationEvent {
-    
+
     private static final long serialVersionUID = -7639844193401892160L;
     private static ObjectMapper mapper = new ObjectMapper();
     private transient final IdentityZone identityZone = IdentityZoneHolder.get();
 
     {
-        mapper.setSerializationConfig(mapper.getSerializationConfig().withSerializationInclusion(Inclusion.NON_NULL));
+        mapper.setConfig(mapper.getSerializationConfig().withSerializationInclusion(JsonInclude.Include.NON_NULL));
     }
 
     private Authentication authentication;
@@ -102,7 +102,7 @@ protected String getOrigin(Principal principal) {
             else {
                 builder.append("caller=").append(caller.getName());
             }
-            
+
 
             if (caller.getDetails() != null) {
                 builder.append(", details=(");
@@ -140,13 +140,13 @@ protected String getOrigin(Principal principal) {
     }
 
     public abstract AuditEvent getAuditEvent();
-    
+
     protected static Authentication getContextAuthentication() {
         Authentication a = SecurityContextHolder.getContext().getAuthentication();
         if (a==null) {
             a = new Authentication() {
                 private static final long serialVersionUID = 1748694836774597624L;
-                
+
                 ArrayList<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                 @Override
                 public Collection<? extends GrantedAuthority> getAuthorities() {
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/ApprovalModifiedEvent.java b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/ApprovalModifiedEvent.java
index 87916cbba4d..e1032c3bfd7 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/ApprovalModifiedEvent.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/ApprovalModifiedEvent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -17,7 +17,7 @@
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.security.core.Authentication;
 
 import java.io.IOException;
@@ -46,8 +46,8 @@ public AuditEvent getAuditEvent() {
 
     private String getData(Approval source) {
         try {
-            return new ObjectMapper().writeValueAsString(new ApprovalModifiedEventData(source));
-        } catch (IOException e) {
+            return JsonUtils.writeValueAsString(new ApprovalModifiedEventData(source));
+        } catch (JsonUtils.JsonUtilException e) {
             logger.error("error writing approval event data", e);
         }
         return null;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/GroupModifiedEvent.java b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/GroupModifiedEvent.java
index db5fc8f71e3..ac87ce4a705 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/GroupModifiedEvent.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/GroupModifiedEvent.java
@@ -15,12 +15,12 @@
 
 package org.cloudfoundry.identity.uaa.audit.event;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
-import org.codehaus.jackson.annotate.JsonCreator;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -74,10 +74,7 @@ public static GroupModifiedEvent groupDeleted(String group, String name, String[
 
     @Override
     public AuditEvent getAuditEvent() {
-        String data = null;
-        try {
-            data = new ObjectMapper().writeValueAsString(new GroupInfo(groupName, members));
-        } catch (IOException e) { }
+        String data = JsonUtils.writeValueAsString(new GroupInfo(groupName, members));
         return createAuditRecord(
             groupId,
             eventType,
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/TokenIssuedEvent.java b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/TokenIssuedEvent.java
index e30315aa598..83b55d82d06 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/TokenIssuedEvent.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/TokenIssuedEvent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,22 +12,20 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.audit.event;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 
 import java.io.IOException;
-import java.security.Principal;
 import java.util.Map;
 
 public class TokenIssuedEvent extends AbstractUaaEvent {
 
-    private ObjectMapper mapper = new ObjectMapper();
 
     public TokenIssuedEvent(OAuth2AccessToken source, Authentication principal) {
         super(source, principal);
@@ -43,21 +41,14 @@ public OAuth2AccessToken getSource() {
 
     @Override
     public AuditEvent getAuditEvent() {
-        String data = null;
-        try {
-            data = mapper.writeValueAsString(getSource().getScope());
-        } catch (IOException e) { }
+        String data = JsonUtils.writeValueAsString(getSource().getScope());
         return createAuditRecord(getPrincipalId(), AuditEventType.TokenIssuedEvent, getOrigin(getAuthentication()), data);
     }
 
     private String getPrincipalId() {
         OAuth2AccessToken token = getSource();
         Jwt jwt = JwtHelper.decode(token.getValue());
-        try {
-            Map<String, Object> claims = mapper.readValue(jwt.getClaims(), new TypeReference<Map<String, Object>>() {});
-            return (claims.get("user_id") != null ? claims.get("user_id") : claims.get("client_id")).toString();
-        } catch (IOException e) {
-            return null;
-        }
+        Map<String, Object> claims = JsonUtils.readValue(jwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+        return (claims.get("user_id") != null ? claims.get("user_id") : claims.get("client_id")).toString();
     }
 }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/UserModifiedEvent.java b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/UserModifiedEvent.java
index 611c4fa3065..43381263ae5 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/UserModifiedEvent.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/UserModifiedEvent.java
@@ -17,7 +17,7 @@
 
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.security.core.Authentication;
 
 import java.io.IOException;
@@ -90,10 +90,7 @@ public static UserModifiedEvent emailChanged(String userId, String username, Str
     @Override
     public AuditEvent getAuditEvent() {
         String[] details = {"user_id="+userId, "username="+username};
-        String data = null;
-        try {
-            data = new ObjectMapper().writeValueAsString(details);
-        } catch (IOException e) { }
+        String data = JsonUtils.writeValueAsString(details);
         return createAuditRecord(
             userId,
             eventType,
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
index 936c3bbdbc1..87115f99432 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -31,10 +31,10 @@
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -70,8 +70,6 @@ public class AuthzAuthenticationFilter implements Filter {
 
     private AuthenticationManager authenticationManager;
 
-    private ObjectMapper mapper = new ObjectMapper();
-
     private List<String> parameterNames = Collections.emptyList();
 
     private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
@@ -190,11 +188,11 @@ private Map<String, String> getCredentials(HttpServletRequest request) {
             if (value != null) {
                 if (value.startsWith("{")) {
                     try {
-                        Map<String, String> jsonCredentials = mapper.readValue(value,
+                        Map<String, String> jsonCredentials = JsonUtils.readValue(value,
                             new TypeReference<Map<String, String>>() {
                             });
                         credentials.putAll(jsonCredentials);
-                    } catch (IOException e) {
+                    } catch (JsonUtils.JsonUtilException e) {
                         logger.warn("Unknown format of value for request param: " + paramName + ". Ignoring.");
                     }
                 }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/ClientParametersAuthenticationFilter.java b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/ClientParametersAuthenticationFilter.java
index f3f10b2f4b0..607cc9760b8 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/ClientParametersAuthenticationFilter.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/ClientParametersAuthenticationFilter.java
@@ -16,9 +16,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
-import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -28,10 +25,8 @@
 import org.springframework.security.oauth2.common.util.OAuth2Utils;
 import org.springframework.security.oauth2.provider.AuthorizationRequest;
 import org.springframework.security.oauth2.provider.OAuth2Authentication;
-import org.springframework.security.oauth2.provider.OAuth2Request;
 import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
 import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.util.Assert;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -40,17 +35,11 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * Filter which processes and authenticates a client based on
@@ -58,7 +47,7 @@
  * It sets the authentication to a client only
  * Oauth2Authentication object as that is expected by
  * the LoginAuthenticationManager.
- * 
+ *
  */
 public class ClientParametersAuthenticationFilter implements Filter {
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
index ede2b43b3c9..05903335d01 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
@@ -27,10 +27,10 @@
 import org.cloudfoundry.identity.uaa.login.saml.IdentityProviderDefinition;
 import org.cloudfoundry.identity.uaa.login.saml.LoginSamlAuthenticationToken;
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.UaaStringUtils;
 import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.springframework.core.env.Environment;
 import org.springframework.core.io.support.PropertiesLoaderUtils;
 import org.springframework.http.HttpStatus;
@@ -53,7 +53,6 @@
 import org.springframework.web.util.UriComponentsBuilder;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpSession;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -400,7 +399,7 @@ public String generatePasscode(Map<String, Object> model, Principal principal)
 
     protected ExpiringCode doGenerateCode(Object o) throws IOException {
         return expiringCodeStore.generateCode(
-            new ObjectMapper().writeValueAsString(o),
+            JsonUtils.writeValueAsString(o),
             new Timestamp(System.currentTimeMillis() + (getCodeExpirationMillis()))
         );
     }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/KeystoneAuthenticationManager.java b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/KeystoneAuthenticationManager.java
index d6ca687fdb3..9f9d02db503 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/KeystoneAuthenticationManager.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/KeystoneAuthenticationManager.java
@@ -15,7 +15,7 @@
 
 package org.cloudfoundry.identity.uaa.authentication.manager;
 
-import org.codehaus.jackson.annotate.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientConstants.java b/common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientConstants.java
index 76e96fc5eb6..9f8de7ae4e0 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientConstants.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientConstants.java
@@ -17,4 +17,5 @@ public class ClientConstants {
     public static final String AUTO_APPROVE = "autoapprove";
     public static final String CREATED_WITH = "createdwith";
     public static final String CLIENT_NAME = "name";
+    public static final String APPROVALS_DELETED = "approvals_deleted";
 }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/client/SocialClientUserDetails.java b/common/src/main/java/org/cloudfoundry/identity/uaa/client/SocialClientUserDetails.java
index 5d534c4fdc3..2afd48921d9 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/client/SocialClientUserDetails.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/client/SocialClientUserDetails.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -14,17 +14,17 @@
 
 import java.util.Collection;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
-import org.codehaus.jackson.annotate.JsonCreator;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 
 /**
  * Customized {@code UserDetails} implementation.
- * 
+ *
  * @author Luke Taylor
  * @author Dave Syer
  */
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/codestore/ExpiringCode.java b/common/src/main/java/org/cloudfoundry/identity/uaa/codestore/ExpiringCode.java
index 004b4e799e5..e4afea35e03 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/codestore/ExpiringCode.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/codestore/ExpiringCode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,11 +12,11 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.codestore;
 
-import java.sql.Timestamp;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
+import java.sql.Timestamp;
 
 @JsonSerialize
 @JsonDeserialize
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrap.java b/common/src/main/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrap.java
index e27c365cf5b..35ca411859c 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrap.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrap.java
@@ -27,7 +27,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
 import org.cloudfoundry.identity.uaa.zone.IdentityProviderProvisioning;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.core.env.Environment;
 import org.springframework.dao.EmptyResultDataAccessException;
@@ -62,8 +61,8 @@ protected void addSamlProviders() {
             provider.setOriginKey(def.getIdpEntityAlias());
             provider.setName("UAA SAML Identity Provider["+provider.getOriginKey()+"]");
             try {
-                provider.setConfig(new ObjectMapper().writeValueAsString(def));
-            } catch (IOException x) {
+                provider.setConfig(JsonUtils.writeValueAsString(def));
+            } catch (JsonUtils.JsonUtilException x) {
                 throw new RuntimeException("Non serializable LDAP config");
             }
             providers.add(provider);
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/config/NestedMapPropertySource.java b/common/src/main/java/org/cloudfoundry/identity/uaa/config/NestedMapPropertySource.java
index 74b0cb1388f..6fc8ba7a36f 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/config/NestedMapPropertySource.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/config/NestedMapPropertySource.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -29,9 +29,9 @@
  * A property source based on a map that might contain nested maps and
  * collections. Property keys can be nested using
  * period separators.
- * 
+ *
  * @author Dave Syer
- * 
+ *
  */
 public class NestedMapPropertySource extends MapPropertySource {
 
@@ -59,10 +59,15 @@ public Object getProperty(String name) {
         return value;
     }
 
+    @Override
+    public boolean containsProperty(String name) {
+        return null != getProperty(name);
+    }
+
     @Override
     public String[] getPropertyNames() {
         populateCache();
-        return this.cache.keySet().toArray(EMPTY_NAMES_ARRAY);
+        return this.cache.keySet().toArray(new String[0]);
     }
 
     private void populateCache() {
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaException.java b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaException.java
index 4d6c6658d15..cfc4117b9e4 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaException.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,16 +12,16 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.error;
 
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-
 /**
  * Base exception for UAA exceptions.
- * 
+ *
  * @author Dave Syer
  */
 @JsonSerialize(using = UaaExceptionSerializer.class)
@@ -71,7 +71,7 @@ public UaaException(Throwable cause, String error, String description, int statu
     }
     /**
      * The error code.
-     * 
+     *
      * @return The error code.
      */
     public String getErrorCode() {
@@ -80,7 +80,7 @@ public String getErrorCode() {
 
     /**
      * The HTTP status associated with this error.
-     * 
+     *
      * @return The HTTP status associated with this error.
      */
     public int getHttpStatus() {
@@ -89,7 +89,7 @@ public int getHttpStatus() {
 
     /**
      * Get any additional information associated with this error.
-     * 
+     *
      * @return Additional information, or null if none.
      */
     public Map<String, String> getAdditionalInformation() {
@@ -98,7 +98,7 @@ public Map<String, String> getAdditionalInformation() {
 
     /**
      * Add some additional information with this OAuth error.
-     * 
+     *
      * @param key The key.
      * @param value The value.
      */
@@ -113,7 +113,7 @@ public void addAdditionalInformation(String key, String value) {
 
     /**
      * Creates an {@link UaaException} from a Map<String,String>.
-     * 
+     *
      * @param errorParams
      * @return
      */
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionDeserializer.java b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionDeserializer.java
index 577dd2954ba..18df7483f91 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionDeserializer.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionDeserializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,26 +12,27 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.error;
 
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
 
 /**
  * @author Dave Syer
- * 
+ *
  */
 public class UaaExceptionDeserializer extends JsonDeserializer<UaaException> {
 
     @Override
     public UaaException deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
 
         int status = 400;
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionSerializer.java b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionSerializer.java
index 4687883ddb9..511eca4e532 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionSerializer.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/error/UaaExceptionSerializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,23 +12,23 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.error;
 
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
 import java.io.IOException;
 import java.util.Map.Entry;
 
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.JsonSerializer;
-import org.codehaus.jackson.map.SerializerProvider;
-
 /**
  * @author Dave Syer
- * 
+ *
  */
 public class UaaExceptionSerializer extends JsonSerializer<UaaException> {
 
     @Override
     public void serialize(UaaException value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
         jgen.writeStartObject();
         jgen.writeStringField("error", value.getErrorCode());
         jgen.writeStringField("error_description", value.getMessage());
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/LdapIdentityProviderDefinition.java b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/LdapIdentityProviderDefinition.java
index 896d5b26d9c..a2bcae8d1ca 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/LdapIdentityProviderDefinition.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/LdapIdentityProviderDefinition.java
@@ -12,7 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.ldap;
 
-import org.codehaus.jackson.annotate.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.springframework.core.env.AbstractEnvironment;
 import org.springframework.core.env.ConfigurableEnvironment;
 import org.springframework.core.env.MapPropertySource;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinRequest.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinRequest.java
index 86bcca4e495..acdc25b04ac 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinRequest.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinRequest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,10 +12,9 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login;
 
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+import com.fasterxml.jackson.annotation.JsonInclude;
 
-@JsonSerialize(include = Inclusion.NON_EMPTY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class AutologinRequest {
 
     private String username;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeAuthenticationFilter.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeAuthenticationFilter.java
index 15a450e5c5a..40f4dc96b12 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeAuthenticationFilter.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeAuthenticationFilter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -28,6 +28,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.authentication.BackwardsCompatibleTokenEndpointAuthenticationFilter;
@@ -39,9 +40,8 @@
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
 import org.cloudfoundry.identity.uaa.user.UaaUser;
 import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -56,7 +56,7 @@
 /**
  * Authentication filter to verify one time passwords with what's cached in the
  * one time password store.
- * 
+ *
  *
  */
 public class PasscodeAuthenticationFilter extends BackwardsCompatibleTokenEndpointAuthenticationFilter {
@@ -65,8 +65,6 @@ public class PasscodeAuthenticationFilter extends BackwardsCompatibleTokenEndpoi
 
     private List<String> parameterNames = Collections.emptyList();
 
-    private final ObjectMapper mapper = new ObjectMapper();
-
     public PasscodeAuthenticationFilter(UaaUserDatabase uaaUserDatabase, AuthenticationManager authenticationManager, OAuth2RequestFactory oAuth2RequestFactory, ExpiringCodeStore expiringCodeStore) {
         super(
             new ExpiringCodeAuthenticationManager(
@@ -191,8 +189,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
                 PasscodeInformation pi = null;
                 if (eCode != null && eCode.getData() != null) {
                     try {
-                        pi = new ObjectMapper().readValue(eCode.getData(), PasscodeInformation.class);
-                    } catch (IOException e) {
+                        pi = JsonUtils.readValue(eCode.getData(), PasscodeInformation.class);
+                    } catch (JsonUtils.JsonUtilException e) {
                         throw new InsufficientAuthenticationException("Unable to deserialize passcode object.", e);
                     }
                 }
@@ -256,11 +254,11 @@ private Map<String, String> getCredentials(HttpServletRequest request) {
             if (value != null) {
                 if (value.startsWith("{")) {
                     try {
-                        Map<String, String> jsonCredentials = mapper.readValue(value,
+                        Map<String, String> jsonCredentials = JsonUtils.readValue(value,
                                         new TypeReference<Map<String, String>>() {
                                         });
                         credentials.putAll(jsonCredentials);
-                    } catch (IOException e) {
+                    } catch (JsonUtils.JsonUtilException e) {
                         logger.warn("Unknown format of value for request param: " + paramName + ". Ignoring.");
                     }
                 }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeInformation.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeInformation.java
index d535fb8ddf2..deb523396a1 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeInformation.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/PasscodeInformation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,16 +12,16 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
-import org.codehaus.jackson.annotate.JsonCreator;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-
 //TODO - make object serialize/deserialize properly with JSON
 public class PasscodeInformation {
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/SamlUserAuthority.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/SamlUserAuthority.java
index 0ede539bfce..d174e4ecb4a 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/SamlUserAuthority.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/SamlUserAuthority.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,8 +12,8 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login;
 
-import org.codehaus.jackson.annotate.JsonCreator;
-import org.codehaus.jackson.annotate.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.springframework.security.core.GrantedAuthority;
 
 @SuppressWarnings("serial")
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/saml/IdentityProviderDefinition.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/saml/IdentityProviderDefinition.java
index 04ea0b0cce9..b911b68e256 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/saml/IdentityProviderDefinition.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/saml/IdentityProviderDefinition.java
@@ -12,8 +12,8 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login.saml;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.cloudfoundry.identity.uaa.login.util.FileLocator;
-import org.codehaus.jackson.annotate.JsonIgnore;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/message/PasswordChangeRequest.java b/common/src/main/java/org/cloudfoundry/identity/uaa/message/PasswordChangeRequest.java
index 333612e5e95..3aed2647ec8 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/message/PasswordChangeRequest.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/message/PasswordChangeRequest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,7 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.message;
 
-import org.codehaus.jackson.map.annotate.JsonSerialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 /**
  * @author Dave Syer
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/CheckTokenEndpoint.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/CheckTokenEndpoint.java
index 2b8da0c8167..128fd767241 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/CheckTokenEndpoint.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/CheckTokenEndpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -14,10 +14,10 @@
 
 import java.util.Map;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.AuthenticationException;
@@ -39,7 +39,7 @@
 /**
  * Controller which decodes access tokens for clients who are not able to do so
  * (or where opaque token values are used).
- * 
+ *
  * @author Luke Taylor
  * @author Joel D'sa
  */
@@ -47,7 +47,6 @@
 public class CheckTokenEndpoint implements InitializingBean {
 
     private ResourceServerTokenServices resourceServerTokenServices;
-    private ObjectMapper mapper = new ObjectMapper();
     protected final Log logger = LogFactory.getLog(getClass());
     private WebResponseExceptionTranslator exceptionTranslator = new DefaultWebResponseExceptionTranslator();
 
@@ -95,9 +94,9 @@ private Map<String, Object> getClaimsForToken(String token) {
 
         Map<String, Object> claims = null;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
             });
-        } catch (Exception e) {
+        } catch (JsonUtils.JsonUtilException e) {
             throw new IllegalStateException("Cannot read token claims", e);
         }
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpoints.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpoints.java
index 62b534a9917..08d30ec0668 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpoints.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpoints.java
@@ -211,7 +211,7 @@ public ClientDetails createClientDetails(@RequestBody BaseClientDetails client)
     @ResponseStatus(HttpStatus.CREATED)
     @ResponseBody
     @Transactional
-    public ClientDetails[] createClientDetailsTx(@RequestBody BaseClientDetails[] clients) throws Exception {
+    public ClientDetails[] createClientDetailsTx(@RequestBody ClientDetailsModification[] clients) throws Exception {
         if (clients==null || clients.length==0) {
             throw new NoSuchClientException("Message body does not contain any clients.");
         }
@@ -234,7 +234,7 @@ protected ClientDetails[] doInsertClientDetails(ClientDetails[] details) {
     @ResponseStatus(HttpStatus.OK)
     @Transactional
     @ResponseBody
-    public ClientDetails[] updateClientDetailsTx(@RequestBody BaseClientDetails[] clients) throws Exception {
+    public ClientDetails[] updateClientDetailsTx(@RequestBody ClientDetailsModification[] clients) throws Exception {
         if (clients==null || clients.length==0) {
             throw new InvalidClientDetailsException("No clients specified for update.");
         }
@@ -295,7 +295,7 @@ public ClientDetails updateClientDetails(@RequestBody BaseClientDetails client,
     @ResponseBody
     public ClientDetails removeClientDetails(@PathVariable String client) throws Exception {
         ClientDetails details = clientDetailsService.retrieve(client);
-        doProcessDeletes(new ClientDetails[] {details});
+        doProcessDeletes(new ClientDetails[]{details});
         return removeSecret(details);
     }
 
@@ -303,7 +303,7 @@ public ClientDetails removeClientDetails(@PathVariable String client) throws Exc
     @ResponseStatus(HttpStatus.OK)
     @Transactional
     @ResponseBody
-    public ClientDetails[] removeClientDetailsTx(@RequestBody BaseClientDetails[] details) throws Exception {
+    public ClientDetails[] removeClientDetailsTx(@RequestBody ClientDetailsModification[] details) throws Exception {
         ClientDetails[] result = new ClientDetails[details.length];
         for (int i=0; i<result.length; i++) {
             result[i] = clientDetailsService.retrieve(details[i].getClientId());
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsService.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsService.java
index 2e298334719..3c5d95b20e8 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsService.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/JdbcQueryableClientDetailsService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -22,8 +22,8 @@
 import org.cloudfoundry.identity.uaa.rest.QueryableResourceManager;
 import org.cloudfoundry.identity.uaa.rest.jdbc.AbstractQueryable;
 import org.cloudfoundry.identity.uaa.rest.jdbc.JdbcPagingListFactory;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowMapper;
 import org.springframework.security.oauth2.provider.client.BaseClientDetails;
@@ -100,7 +100,6 @@ public ClientDetails delete(String id, int version) {
     }
 
     private static class ClientDetailsRowMapper implements RowMapper<ClientDetails> {
-        private ObjectMapper mapper = new ObjectMapper();
 
         @Override
         public ClientDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
@@ -117,7 +116,7 @@ public ClientDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
             if (json != null) {
                 try {
                     @SuppressWarnings("unchecked")
-                    Map<String, Object> additionalInformation = mapper.readValue(json, Map.class);
+                    Map<String, Object> additionalInformation = JsonUtils.readValue(json, Map.class);
                     details.setAdditionalInformation(additionalInformation);
                 } catch (Exception e) {
                     logger.warn("Could not decode JSON for additional information: " + details, e);
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServices.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServices.java
index b8982e94109..4093c9e9b96 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServices.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServices.java
@@ -23,7 +23,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
@@ -69,8 +69,6 @@ public class RemoteTokenServices implements ResourceServerTokenServices {
 
     private String clientSecret;
 
-    private ObjectMapper mapper = new ObjectMapper();
-
     private boolean storeClaims = false;
 
     public RemoteTokenServices() {
@@ -170,8 +168,8 @@ public OAuth2Authentication loadAuthentication(String accessToken) throws Authen
 
         if (map.containsKey(Claims.ADDITIONAL_AZ_ATTR)) {
             try {
-                requestParameters.put(Claims.ADDITIONAL_AZ_ATTR, mapper.writeValueAsString(map.get(Claims.ADDITIONAL_AZ_ATTR)));
-            } catch (IOException e) {
+                requestParameters.put(Claims.ADDITIONAL_AZ_ATTR, JsonUtils.writeValueAsString(map.get(Claims.ADDITIONAL_AZ_ATTR)));
+            } catch (JsonUtils.JsonUtilException e) {
                 throw new IllegalStateException("Cannot convert access token to JSON", e);
             }
         }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/SecretChangeRequest.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/SecretChangeRequest.java
index 05082c7e786..793119ac379 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/SecretChangeRequest.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/SecretChangeRequest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,13 +12,14 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.oauth;
 
-import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
 
 /**
  * @author Dave Syer
  * @author Luke Taylor
  */
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class SecretChangeRequest {
 
     private String oldSecret;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/approval/Approval.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/approval/Approval.java
index c77ca39bac8..eb6ba17dbff 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/approval/Approval.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/approval/Approval.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -15,13 +15,14 @@
 import java.util.Calendar;
 import java.util.Date;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.cloudfoundry.identity.uaa.util.json.JsonDateDeserializer;
 import org.cloudfoundry.identity.uaa.util.json.JsonDateSerializer;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class Approval {
 
     private String userId;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModification.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModification.java
index 31302be94f2..39296bb1bcb 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModification.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModification.java
@@ -1,13 +1,14 @@
 package org.cloudfoundry.identity.uaa.oauth.client;
 
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonIgnoreProperties;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
-import org.springframework.security.oauth2.provider.client.BaseClientDetails;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.cloudfoundry.identity.uaa.client.ClientConstants;
 import org.springframework.security.oauth2.provider.ClientDetails;
+import org.springframework.security.oauth2.provider.client.BaseClientDetails;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_DEFAULT)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class ClientDetailsModification extends BaseClientDetails {
 
@@ -20,8 +21,6 @@ public class ClientDetailsModification extends BaseClientDetails {
 
     @JsonProperty("action")
     private String action = NONE;
-    @JsonProperty("approvals_deleted")
-    private boolean approvalsDeleted = false;
 
     public ClientDetailsModification() {
     }
@@ -65,12 +64,15 @@ public void setAction(String action) {
 
     @JsonIgnore
     public boolean isApprovalsDeleted() {
-        return approvalsDeleted;
+        if (getAdditionalInformation().get(ClientConstants.APPROVALS_DELETED)!=null) {
+            return Boolean.TRUE.equals(getAdditionalInformation().get(ClientConstants.APPROVALS_DELETED));
+        }
+        return false;
     }
 
     @JsonIgnore
     public void setApprovalsDeleted(boolean approvalsDeleted) {
-        this.approvalsDeleted = approvalsDeleted;
+        addAdditionalInformation(ClientConstants.APPROVALS_DELETED, approvalsDeleted);
     }
 
     @JsonIgnore
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/expression/ContextSensitiveOAuth2SecurityExpressionMethods.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/expression/ContextSensitiveOAuth2SecurityExpressionMethods.java
index f563e87f280..a920ed323fe 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/expression/ContextSensitiveOAuth2SecurityExpressionMethods.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/expression/ContextSensitiveOAuth2SecurityExpressionMethods.java
@@ -12,14 +12,12 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.oauth.expression;
 
-import java.util.Map;
-
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
 import org.cloudfoundry.identity.uaa.oauth.Claims;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
@@ -27,6 +25,8 @@
 import org.springframework.security.oauth2.provider.expression.OAuth2SecurityExpressionMethods;
 import org.springframework.util.StringUtils;
 
+import java.util.Map;
+
 public class ContextSensitiveOAuth2SecurityExpressionMethods extends OAuth2SecurityExpressionMethods {
     public static final String ZONE_ID = "{zone.id}";
 
@@ -120,8 +120,8 @@ private String getZoneIdFromToken(String token) {
         }
         Map<String, Object> claims = null;
         try {
-            claims = new ObjectMapper().readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
-        } catch (Exception e) {
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+        } catch (JsonUtils.JsonUtilException e) {
             throw new IllegalStateException("Cannot read token claims", e);
         }
         return (String)claims.get(Claims.ZONE_ID);
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/OpenIdToken.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/OpenIdToken.java
index d0ae54b06b2..a08691a6b7c 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/OpenIdToken.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/OpenIdToken.java
@@ -18,14 +18,16 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.SerializerProvider;
-import org.codehaus.jackson.map.deser.StdDeserializer;
-import org.codehaus.jackson.map.ser.SerializerBase;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
 import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
@@ -33,8 +35,8 @@
 import org.springframework.security.oauth2.common.util.OAuth2Utils;
 import org.springframework.util.Assert;
 
-@org.codehaus.jackson.map.annotate.JsonSerialize(using = OpenIdToken.OpenIdTokenJackson1Serializer.class)
-@org.codehaus.jackson.map.annotate.JsonDeserialize(using = OpenIdToken.OpenIdTokenJackson1Deserializer.class)
+@JsonSerialize(using = OpenIdToken.OpenIdTokenJackson1Serializer.class)
+@JsonDeserialize(using = OpenIdToken.OpenIdTokenJackson1Deserializer.class)
 public class OpenIdToken extends DefaultOAuth2AccessToken {
 
     public static String ID_TOKEN = "id_token";
@@ -57,7 +59,7 @@ public OpenIdToken(OAuth2AccessToken accessToken) {
         super(accessToken);
     }
 
-    public static final class OpenIdTokenJackson1Serializer extends SerializerBase<OAuth2AccessToken> {
+    public static final class OpenIdTokenJackson1Serializer extends StdSerializer<OAuth2AccessToken> {
 
         public OpenIdTokenJackson1Serializer() {
             super(OAuth2AccessToken.class);
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServices.java b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServices.java
index d6a5f170159..67d4b6a5a61 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServices.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServices.java
@@ -12,6 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.oauth.token;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.audit.event.TokenIssuedEvent;
@@ -25,10 +26,9 @@
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
 import org.cloudfoundry.identity.uaa.user.UaaUser;
 import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.UaaTokenUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.ApplicationEventPublisherAware;
@@ -115,8 +115,6 @@ public class UaaTokenServices implements AuthorizationServerTokenServices, Resou
 
     private UaaUserDatabase userDatabase = null;
 
-    private ObjectMapper mapper = new ObjectMapper();
-
     private ClientDetailsService clientDetailsService = null;
 
     private SignerProvider signerProvider = new SignerProvider();
@@ -306,9 +304,9 @@ private OAuth2AccessToken createAccessToken(String userId, String username, Stri
 
         String content;
         try {
-            content = mapper.writeValueAsString(createJWTAccessToken(accessToken, userId, username, userEmail,
-                            clientScopes, requestedScopes, clientId, resourceIds, grantType, refreshToken));
-        } catch (Exception e) {
+            content = JsonUtils.writeValueAsString(createJWTAccessToken(accessToken, userId, username, userEmail,
+                clientScopes, requestedScopes, clientId, resourceIds, grantType, refreshToken));
+        } catch (JsonUtils.JsonUtilException e) {
             throw new IllegalStateException("Cannot convert access token to JSON", e);
         }
         String token = JwtHelper.encode(content, signerProvider.getSigner()).getEncoded();
@@ -467,7 +465,7 @@ private Map<String, String> getAdditionalAuthorizationAttributes(String authorit
         if (StringUtils.hasLength(authoritiesJson)) {
             try {
                 @SuppressWarnings("unchecked")
-                Map<String, Object> authorities = mapper.readValue(authoritiesJson.getBytes(), Map.class);
+                Map<String, Object> authorities = JsonUtils.readValue(authoritiesJson, new TypeReference<Map<String, Object>>() {});
                 @SuppressWarnings("unchecked")
                 Map<String, String> additionalAuthorizationAttributes = (Map<String, String>) authorities
                                 .get("az_attr");
@@ -500,14 +498,14 @@ private ExpiringOAuth2RefreshToken createRefreshToken(OAuth2Authentication authe
 
         String content;
         try {
-            content = mapper.writeValueAsString(
+            content = JsonUtils.writeValueAsString(
                 createJWTRefreshToken(
                     token, user, authentication.getOAuth2Request().getScope(),
                     authentication.getOAuth2Request().getClientId(),
                     grantType, additionalAuthorizationAttributes,authentication.getOAuth2Request().getResourceIds()
                 )
             );
-        } catch (Exception e) {
+        } catch (JsonUtils.JsonUtilException e) {
             throw new IllegalStateException("Cannot convert access token to JSON", e);
         }
         String jwtToken = JwtHelper.encode(content, signerProvider.getSigner()).getEncoded();
@@ -771,9 +769,9 @@ private Map<String, Object> getClaimsForToken(String token) {
 
         Map<String, Object> claims = null;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
             });
-        } catch (Exception e) {
+        } catch (JsonUtils.JsonUtilException e) {
             throw new IllegalStateException("Cannot read token claims", e);
         }
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/TokenEndpointPostProcessor.java b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/TokenEndpointPostProcessor.java
new file mode 100644
index 00000000000..427041f6d0b
--- /dev/null
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/TokenEndpointPostProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * *****************************************************************************
+ *      Cloud Foundry
+ *      Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
+ *      This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ *      You may not use this product except in compliance with the License.
+ *
+ *      This product includes a number of subcomponents with
+ *      separate copyright notices and license terms. Your use of these
+ *      subcomponents is subject to the terms and conditions of the
+ *      subcomponent's license, as noted in the LICENSE file.
+ * *****************************************************************************
+ */
+
+package org.cloudfoundry.identity.uaa.security.web;
+
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class TokenEndpointPostProcessor implements BeanPostProcessor {
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+        return bean;
+    }
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        if (bean != null && bean instanceof TokenEndpoint) {
+            TokenEndpoint endpoint = (TokenEndpoint)bean;
+            Set<HttpMethod> methods = new HashSet<>();
+            methods.add(HttpMethod.POST);
+            methods.add(HttpMethod.GET);
+            endpoint.setAllowedRequestMethods(methods);
+        }
+        return bean;
+    }
+}
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaAuthority.java b/common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaAuthority.java
index 19f61a1d3cc..19bcd63deb8 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaAuthority.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaAuthority.java
@@ -16,7 +16,7 @@
 import java.util.Collections;
 import java.util.List;
 
-import org.codehaus.jackson.annotate.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonCreator;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/util/JsonUtils.java b/common/src/main/java/org/cloudfoundry/identity/uaa/util/JsonUtils.java
index 15aec9b38ec..3fdab46a186 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/util/JsonUtils.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/util/JsonUtils.java
@@ -12,10 +12,13 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.util;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import java.io.IOException;
 
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 
 public class JsonUtils {
     private static ObjectMapper objectMapper = new ObjectMapper();
@@ -60,6 +63,16 @@ public static <T> T convertValue(Object object, Class<T> toClazz) throws JsonUti
         }
     }
 
+    public static JsonNode readTree(String s) {
+        try {
+            return objectMapper.readTree(s);
+        } catch (JsonProcessingException e) {
+            throw new JsonUtilException(e);
+        } catch (IOException e) {
+            throw new JsonUtilException(e);
+        }
+    }
+
     public static class JsonUtilException extends RuntimeException {
 
         private static final long serialVersionUID = -4804245225960963421L;
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateDeserializer.java b/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateDeserializer.java
index 89e0e8c381c..c3df8de4df1 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateDeserializer.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateDeserializer.java
@@ -12,17 +12,17 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.util.json;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
 import java.io.IOException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
-
 /**
  * JSON deserializer for Jackson to handle regular date instances as timestamps
  * in ISO format.
@@ -36,7 +36,7 @@ public class JsonDateDeserializer extends JsonDeserializer<Date> {
 
     @Override
     public Date deserialize(JsonParser parser, DeserializationContext context) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
         try {
             return dateFormat.parse(parser.getText());
         } catch (ParseException e) {
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateSerializer.java b/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateSerializer.java
index 5d2c0378de8..7186a0afc40 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateSerializer.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/util/json/JsonDateSerializer.java
@@ -12,15 +12,15 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.util.json;
 
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.JsonSerializer;
-import org.codehaus.jackson.map.SerializerProvider;
-
 /**
  * JSON serializer for Jackson to handle regular date instances as timestamps in
  * ISO format.
@@ -34,7 +34,7 @@ public class JsonDateSerializer extends JsonSerializer<Date> {
 
     @Override
     public void serialize(Date date, JsonGenerator generator, SerializerProvider provider) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
         String formatted = dateFormat.format(date);
         generator.writeString(formatted);
     }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProvider.java b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProvider.java
index 8d4c0a7591b..51a1830f86d 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProvider.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProvider.java
@@ -15,10 +15,10 @@
 import javax.validation.constraints.NotNull;
 import java.util.Date;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.util.JsonUtils;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.type.TypeReference;
 
 public class IdentityProvider {
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProviderValidationRequest.java b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProviderValidationRequest.java
index d907d9e7235..d8957b9173d 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProviderValidationRequest.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityProviderValidationRequest.java
@@ -12,9 +12,9 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.zone;
 
-import org.codehaus.jackson.annotate.JsonCreator;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityZone.java b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityZone.java
index 1ef750319db..746f1d2dfa9 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityZone.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/IdentityZone.java
@@ -12,10 +12,10 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.zone;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
 import javax.validation.constraints.NotNull;
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java
index 09c0b293ba8..712fed9b262 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/zone/MultitenantJdbcClientDetailsService.java
@@ -12,22 +12,10 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.zone;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.sql.DataSource;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.rest.ResourceMonitor;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -46,9 +34,18 @@
 import org.springframework.security.oauth2.provider.client.BaseClientDetails;
 import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
 import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
 import org.springframework.util.StringUtils;
 
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 /**
  * A copy of JdbcClientDetailsService but with IdentityZone awareness
  */
@@ -299,23 +296,19 @@ interface JsonMapper {
     }
 
     private static JsonMapper createJsonMapper() {
-        if (ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", null)) {
-            return new JacksonMapper();
-        }
-        return new NotSupportedJsonMapper();
+        return new JacksonMapper();
     }
 
     private static class JacksonMapper implements JsonMapper {
-        private org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
 
         @Override
         public String write(Object input) throws Exception {
-            return mapper.writeValueAsString(input);
+            return JsonUtils.writeValueAsString(input);
         }
 
         @Override
         public <T> T read(String input, Class<T> type) throws Exception {
-            return mapper.readValue(input, type);
+            return JsonUtils.readValue(input, type);
         }
     }
 
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrapTest.java b/common/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrapTest.java
index 21b1fda4be3..cd64137a225 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrapTest.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityProviderBootstrapTest.java
@@ -14,33 +14,33 @@
 
 package org.cloudfoundry.identity.uaa.config;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.login.saml.IdentityProviderConfigurator;
 import org.cloudfoundry.identity.uaa.login.saml.IdentityProviderDefinition;
 import org.cloudfoundry.identity.uaa.test.JdbcTestBase;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
 import org.cloudfoundry.identity.uaa.zone.IdentityProviderProvisioning;
-import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.JdbcIdentityProviderProvisioning;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.mock.env.MockEnvironment;
 
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 public class IdentityProviderBootstrapTest extends JdbcTestBase {
 
     @After
@@ -79,7 +79,7 @@ public void testLdapBootstrap() throws Exception {
 
         IdentityProvider ldapProvider = provisioning.retrieveByOrigin(Origin.LDAP, IdentityZoneHolder.get().getId());
         assertNotNull(ldapProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(ldapConfig), ldapProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(ldapConfig), ldapProvider.getConfig());
         assertNotNull(ldapProvider.getCreated());
         assertNotNull(ldapProvider.getLastModified());
         assertEquals(Origin.LDAP, ldapProvider.getType());
@@ -96,7 +96,7 @@ public void testRemovedLdapBootstrapIsInactive() throws Exception {
 
         IdentityProvider ldapProvider = provisioning.retrieveByOrigin(Origin.LDAP, IdentityZoneHolder.get().getId());
         assertNotNull(ldapProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(ldapConfig), ldapProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(ldapConfig), ldapProvider.getConfig());
         assertNotNull(ldapProvider.getCreated());
         assertNotNull(ldapProvider.getLastModified());
         assertEquals(Origin.LDAP, ldapProvider.getType());
@@ -115,7 +115,7 @@ public void testRemovedLdapBootstrapIsInactive() throws Exception {
         bootstrap.afterPropertiesSet();
         ldapProvider = provisioning.retrieveByOrigin(Origin.LDAP, IdentityZoneHolder.get().getId());
         assertNotNull(ldapProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(ldapConfig), ldapProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(ldapConfig), ldapProvider.getConfig());
         assertNotNull(ldapProvider.getCreated());
         assertNotNull(ldapProvider.getLastModified());
         assertEquals(Origin.LDAP, ldapProvider.getType());
@@ -153,7 +153,7 @@ public void testKeystoneBootstrap() throws Exception {
 
         IdentityProvider keystoneProvider = provisioning.retrieveByOrigin(Origin.KEYSTONE, IdentityZoneHolder.get().getId());
         assertNotNull(keystoneProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
         assertNotNull(keystoneProvider.getCreated());
         assertNotNull(keystoneProvider.getLastModified());
         assertEquals(Origin.KEYSTONE, keystoneProvider.getType());
@@ -170,7 +170,7 @@ public void testRemovedKeystoneBootstrapIsInactive() throws Exception {
 
         IdentityProvider keystoneProvider = provisioning.retrieveByOrigin(Origin.KEYSTONE, IdentityZoneHolder.get().getId());
         assertNotNull(keystoneProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
         assertNotNull(keystoneProvider.getCreated());
         assertNotNull(keystoneProvider.getLastModified());
         assertEquals(Origin.KEYSTONE, keystoneProvider.getType());
@@ -189,7 +189,7 @@ public void testRemovedKeystoneBootstrapIsInactive() throws Exception {
         bootstrap.afterPropertiesSet();
         keystoneProvider = provisioning.retrieveByOrigin(Origin.KEYSTONE, IdentityZoneHolder.get().getId());
         assertNotNull(keystoneProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(keystoneConfig), keystoneProvider.getConfig());
         assertNotNull(keystoneProvider.getCreated());
         assertNotNull(keystoneProvider.getLastModified());
         assertEquals(Origin.KEYSTONE, keystoneProvider.getType());
@@ -219,7 +219,7 @@ public void testSamlBootstrap() throws Exception {
         IdentityProvider samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
         definition.setZoneId(IdentityZoneHolder.get().getId());
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -252,7 +252,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
         IdentityProvider samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
         definition.setZoneId(IdentityZoneHolder.get().getId());
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -261,7 +261,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
         IdentityProvider samlProvider2 = provisioning.retrieveByOrigin(definition2.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider2);
         definition2.setZoneId(IdentityZoneHolder.get().getId());
-        assertEquals(new ObjectMapper().writeValueAsString(definition2), samlProvider2.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition2), samlProvider2.getConfig());
         assertNotNull(samlProvider2.getCreated());
         assertNotNull(samlProvider2.getLastModified());
         assertEquals(Origin.SAML, samlProvider2.getType());
@@ -274,7 +274,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -282,7 +282,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider2 = provisioning.retrieveByOrigin(definition2.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider2);
-        assertEquals(new ObjectMapper().writeValueAsString(definition2), samlProvider2.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition2), samlProvider2.getConfig());
         assertNotNull(samlProvider2.getCreated());
         assertNotNull(samlProvider2.getLastModified());
         assertEquals(Origin.SAML, samlProvider2.getType());
@@ -295,7 +295,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -303,7 +303,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider2 = provisioning.retrieveByOrigin(definition2.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider2);
-        assertEquals(new ObjectMapper().writeValueAsString(definition2), samlProvider2.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition2), samlProvider2.getConfig());
         assertNotNull(samlProvider2.getCreated());
         assertNotNull(samlProvider2.getLastModified());
         assertEquals(Origin.SAML, samlProvider2.getType());
@@ -316,7 +316,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -324,7 +324,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider2 = provisioning.retrieveByOrigin(definition2.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider2);
-        assertEquals(new ObjectMapper().writeValueAsString(definition2), samlProvider2.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition2), samlProvider2.getConfig());
         assertNotNull(samlProvider2.getCreated());
         assertNotNull(samlProvider2.getLastModified());
         assertEquals(Origin.SAML, samlProvider2.getType());
@@ -337,7 +337,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider = provisioning.retrieveByOrigin(definition.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider);
-        assertEquals(new ObjectMapper().writeValueAsString(definition), samlProvider.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition), samlProvider.getConfig());
         assertNotNull(samlProvider.getCreated());
         assertNotNull(samlProvider.getLastModified());
         assertEquals(Origin.SAML, samlProvider.getType());
@@ -345,7 +345,7 @@ public void testRemovedSamlBootstrapIsInactive() throws Exception {
 
         samlProvider2 = provisioning.retrieveByOrigin(definition2.getIdpEntityAlias(), IdentityZoneHolder.get().getId());
         assertNotNull(samlProvider2);
-        assertEquals(new ObjectMapper().writeValueAsString(definition2), samlProvider2.getConfig());
+        assertEquals(JsonUtils.writeValueAsString(definition2), samlProvider2.getConfig());
         assertNotNull(samlProvider2.getCreated());
         assertNotNull(samlProvider2.getLastModified());
         assertEquals(Origin.SAML, samlProvider2.getType());
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpointsTests.java b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpointsTests.java
index f9cd82b8cb0..efc0e732e54 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpointsTests.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpointsTests.java
@@ -33,6 +33,7 @@
 import org.cloudfoundry.identity.uaa.error.UaaException;
 import org.cloudfoundry.identity.uaa.oauth.ClientDetailsValidator.Mode;
 import org.cloudfoundry.identity.uaa.oauth.approval.ApprovalStore;
+import org.cloudfoundry.identity.uaa.oauth.client.ClientDetailsModification;
 import org.cloudfoundry.identity.uaa.rest.QueryableResourceManager;
 import org.cloudfoundry.identity.uaa.rest.ResourceMonitor;
 import org.cloudfoundry.identity.uaa.rest.SearchResults;
@@ -68,7 +69,7 @@ public class ClientAdminEndpointsTests {
 
     private BaseClientDetails input = null;
 
-    private BaseClientDetails[] inputs = new BaseClientDetails[5];
+    private ClientDetailsModification[] inputs = new ClientDetailsModification[5];
 
     private BaseClientDetails detail = null;
 
@@ -129,7 +130,7 @@ public void setUp() throws Exception {
         input.setAuthorizedGrantTypes(Arrays.asList("authorization_code"));
 
         for (int i=0; i<inputs.length; i++) {
-            inputs[i] = new BaseClientDetails();
+            inputs[i] = new ClientDetailsModification();
             inputs[i].setClientId("foo-"+i);
             inputs[i].setClientSecret("secret-"+i);
             inputs[i].setAuthorizedGrantTypes(Arrays.asList("authorization_code"));
@@ -208,13 +209,13 @@ public void testMultipleCreateClientDetailsNullArray() throws Exception {
 
     @Test(expected = NoSuchClientException.class)
     public void testMultipleCreateClientDetailsEmptyArray() throws Exception {
-        endpoints.createClientDetailsTx(new BaseClientDetails[0]);
+        endpoints.createClientDetailsTx(new ClientDetailsModification[0]);
     }
 
     @Test(expected = InvalidClientDetailsException.class)
     public void testMultipleCreateClientDetailsNonExistent() throws Exception {
-        BaseClientDetails nonexist = new BaseClientDetails("unknown","","","","");
-        endpoints.createClientDetailsTx(new BaseClientDetails[]{nonexist});
+        ClientDetailsModification nonexist = new ClientDetailsModification("unknown","","","","");
+        endpoints.createClientDetailsTx(new ClientDetailsModification[]{nonexist});
     }
 
     @Test(expected = InvalidClientDetailsException.class)
@@ -224,7 +225,7 @@ public void testMultipleUpdateClientDetailsNullArray() throws Exception {
 
     @Test(expected = InvalidClientDetailsException.class)
     public void testMultipleUpdateClientDetailsEmptyArray() throws Exception {
-        endpoints.updateClientDetailsTx(new BaseClientDetails[0]);
+        endpoints.updateClientDetailsTx(new ClientDetailsModification[0]);
     }
 
 
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServicesTests.java b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServicesTests.java
index 9850362dad7..85109df64e9 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServicesTests.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/RemoteTokenServicesTests.java
@@ -20,7 +20,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.Test;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
@@ -104,14 +104,13 @@ public void testTokenRetrievalWithUserAuthorities() throws Exception {
 
     @Test
     public void testTokenRetrievalWithAdditionalAuthorizationAttributes() throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
         Map additionalAuthorizationAttributesMap = Collections.singletonMap("test", 1);
         body.put(Claims.ADDITIONAL_AZ_ATTR, additionalAuthorizationAttributesMap);
 
         OAuth2Authentication result = services.loadAuthentication("FOO");
 
         assertNotNull(result);
-        assertEquals(mapper.writeValueAsString(additionalAuthorizationAttributesMap), result.getOAuth2Request()
+        assertEquals(JsonUtils.writeValueAsString(additionalAuthorizationAttributesMap), result.getOAuth2Request()
                         .getRequestParameters().get(Claims.ADDITIONAL_AZ_ATTR));
     }
 }
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModificationTests.java b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModificationTests.java
new file mode 100644
index 00000000000..ee1d019e125
--- /dev/null
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/client/ClientDetailsModificationTests.java
@@ -0,0 +1,47 @@
+/*
+ * *****************************************************************************
+ *      Cloud Foundry
+ *      Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
+ *      This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ *      You may not use this product except in compliance with the License.
+ *
+ *      This product includes a number of subcomponents with
+ *      separate copyright notices and license terms. Your use of these
+ *      subcomponents is subject to the terms and conditions of the
+ *      subcomponent's license, as noted in the LICENSE file.
+ * *****************************************************************************
+ */
+
+package org.cloudfoundry.identity.uaa.oauth.client;
+
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Created by fhanik on 5/5/15.
+ */
+public class ClientDetailsModificationTests {
+
+    @Test
+    public void testClientDetailsModificationDeserialize() throws Exception {
+        String data = "{\"scope\":\n" +
+            "        [\"bar\",\"foo\",\"oauth.approvals\"],\n" +
+            "        \"client_id\":\"Kn30XB\",\n" +
+            "        \"resource_ids\":[\"none\"],\n" +
+            "        \"authorized_grant_types\":[\"password\",\"refresh_token\"],\n" +
+            "        \"autoapprove\":[],\n" +
+            "        \"action\":\"none\",\n" +
+            "        \"approvals_deleted\":true,\n" +
+            "        \"authorities\":[\"uaa.none\"],\n" +
+            "        \"action\":\"none\",\n" +
+            "        \"foo\":[\"bar\"],\n" +
+            "        \"lastModified\":1430849491767\n" +
+            "    }";
+
+        ClientDetailsModification details = JsonUtils.readValue(data, ClientDetailsModification.class);
+        assertTrue(details.isApprovalsDeleted());
+
+    }
+}
\ No newline at end of file
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServicesTests.java b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServicesTests.java
index eb83915f11d..24d52157306 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServicesTests.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/oauth/token/UaaTokenServicesTests.java
@@ -12,6 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.oauth.token;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.audit.AuditEvent;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
 import org.cloudfoundry.identity.uaa.audit.event.TokenIssuedEvent;
@@ -28,10 +29,9 @@
 import org.cloudfoundry.identity.uaa.user.InMemoryUaaUserDatabase;
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
 import org.cloudfoundry.identity.uaa.user.UaaUser;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -100,7 +100,6 @@ public class UaaTokenServicesTests {
     private TestApplicationEventPublisher<TokenIssuedEvent> publisher;
     private UaaTokenServices tokenServices = new UaaTokenServices();
     private SignerProvider signerProvider = new SignerProvider();
-    private ObjectMapper mapper = new ObjectMapper();
     
     private List<GrantedAuthority> defaultUserAuthorities = Arrays.asList(
         UaaAuthority.authority("space.123.developer"),
@@ -236,7 +235,8 @@ public void testCreateAccessTokenForAClient() {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
+            });
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -284,7 +284,7 @@ public void testCreateAccessTokenForAClientInAnotherIdentityZone() {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -382,7 +382,7 @@ public void testCreateAccessTokenRefreshGrant() throws InterruptedException {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -433,7 +433,7 @@ public void testCreateAccessTokenRefreshGrantAllScopesAutoApproved() throws Inte
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -484,7 +484,7 @@ public void testCreateAccessTokenRefreshGrantSomeScopesAutoApprovedDowngradedReq
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -541,7 +541,7 @@ public void testCreateAccessTokenRefreshGrantSomeScopesAutoApproved() throws Int
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -666,7 +666,7 @@ private OAuth2AccessToken testCreateAccessTokenForAUser(OAuth2Authentication aut
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -693,7 +693,7 @@ private OAuth2AccessToken testCreateAccessTokenForAUser(OAuth2Authentication aut
             assertNotNull(refreshTokenJwt);
             Map<String, Object> refreshTokenClaims;
             try {
-                refreshTokenClaims = mapper.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+                refreshTokenClaims = JsonUtils.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
             } catch (Exception e) {
                 throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
             }
@@ -761,7 +761,7 @@ public void testCreateAccessTokenAuthcodeGrantNarrowerScopes() {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -773,7 +773,7 @@ public void testCreateAccessTokenAuthcodeGrantNarrowerScopes() {
         assertNotNull(refreshTokenJwt);
         Map<String, Object> refreshTokenClaims;
         try {
-            refreshTokenClaims = mapper.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            refreshTokenClaims = JsonUtils.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -796,7 +796,7 @@ public void testCreateAccessTokenAuthcodeGrantNarrowerScopes() {
         assertNotNull(tokenJwt);
         Map<String, Object> reducedClaims;
         try {
-            reducedClaims = mapper.readValue(newTokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            reducedClaims = JsonUtils.readValue(newTokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -826,7 +826,7 @@ public void testCreateAccessTokenAuthcodeGrantExpandedScopes() {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -838,7 +838,7 @@ public void testCreateAccessTokenAuthcodeGrantExpandedScopes() {
         assertNotNull(refreshTokenJwt);
         Map<String, Object> refreshTokenClaims;
         try {
-            refreshTokenClaims = mapper.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            refreshTokenClaims = JsonUtils.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -877,7 +877,7 @@ public void testChangedExpiryForTokens() {
         assertNotNull(tokenJwt);
         Map<String, Object> claims;
         try {
-            claims = mapper.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
@@ -891,7 +891,7 @@ public void testChangedExpiryForTokens() {
         assertNotNull(refreshTokenJwt);
         Map<String, Object> refreshTokenClaims;
         try {
-            refreshTokenClaims = mapper.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
+            refreshTokenClaims = JsonUtils.readValue(refreshTokenJwt.getClaims(),new TypeReference<Map<String, Object>>() {});
         } catch (Exception e) {
             throw new IllegalStateException(CANNOT_READ_TOKEN_CLAIMS, e);
         }
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/rest/MessageTests.java b/common/src/test/java/org/cloudfoundry/identity/uaa/rest/MessageTests.java
index fbdb654b475..01ac497fc96 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/rest/MessageTests.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/rest/MessageTests.java
@@ -18,7 +18,7 @@
 import java.io.StringWriter;
 
 import org.cloudfoundry.identity.uaa.message.SimpleMessage;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.Test;
 
 /**
@@ -30,15 +30,13 @@ public class MessageTests {
 
     @Test
     public void testSerialize() throws Exception {
-        StringWriter writer = new StringWriter();
-        new ObjectMapper().writeValue(writer, new SimpleMessage("ok", "done"));
-        assertEquals("{\"status\":\"ok\",\"message\":\"done\"}", writer.toString());
+        assertEquals("{\"status\":\"ok\",\"message\":\"done\"}", JsonUtils.writeValueAsString(new SimpleMessage("ok", "done")));
     }
 
     @Test
     public void testDeserialize() throws Exception {
         String value = "{\"status\":\"ok\",\"message\":\"done\"}";
-        SimpleMessage message = new ObjectMapper().readValue(value, SimpleMessage.class);
+        SimpleMessage message = JsonUtils.readValue(value, SimpleMessage.class);
         assertEquals(new SimpleMessage("ok", "done"), message);
     }
 
diff --git a/common/src/test/java/org/cloudfoundry/identity/uaa/test/TestAccountSetup.java b/common/src/test/java/org/cloudfoundry/identity/uaa/test/TestAccountSetup.java
index 07fde31eebd..16eead0f5b0 100644
--- a/common/src/test/java/org/cloudfoundry/identity/uaa/test/TestAccountSetup.java
+++ b/common/src/test/java/org/cloudfoundry/identity/uaa/test/TestAccountSetup.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -39,7 +39,7 @@
 import org.springframework.http.client.SimpleClientHttpRequestFactory;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.StringHttpMessageConverter;
-import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
@@ -56,7 +56,7 @@
 
 /**
  * @author Dave Syer
- * 
+ *
  */
 public class TestAccountSetup extends TestWatchman {
 
@@ -278,7 +278,7 @@ public void handleError(ClientHttpResponse response) throws IOException {
         });
         List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
         list.add(new StringHttpMessageConverter());
-        list.add(new MappingJacksonHttpMessageConverter());
+        list.add(new MappingJackson2HttpMessageConverter());
         client.setMessageConverters(list);
         return client;
     }
diff --git a/gradle.properties b/gradle.properties
index 544df399390..65362284ef9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +1 @@
-version=2.2.7-SNAPSHOT
+version=2.3.0-SNAPSHOT
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/AccountCreationService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/AccountCreationService.java
index 6a34aa62337..276922c8baf 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/AccountCreationService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/AccountCreationService.java
@@ -1,7 +1,7 @@
 package org.cloudfoundry.identity.uaa.login;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
-import org.codehaus.jackson.annotate.JsonProperty;
 
 import java.io.IOException;
 
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinAuthenticationManager.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinAuthenticationManager.java
index 5925f8167cc..d9c384984fe 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinAuthenticationManager.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/AutologinAuthenticationManager.java
@@ -13,9 +13,6 @@
 
 package org.cloudfoundry.identity.uaa.login;
 
-import java.io.IOException;
-import java.util.Map;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationRequest;
@@ -25,20 +22,16 @@
 import org.cloudfoundry.identity.uaa.client.SocialClientUserDetails;
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.web.client.RestTemplate;
+
+import java.io.IOException;
+import java.util.Map;
 
 /**
  * @author Dave Syer
@@ -77,9 +70,9 @@ public Authentication authenticate(Authentication authentication) throws Authent
         SocialClientUserDetails user = null;
         try {
             if (ec != null) {
-                user = new ObjectMapper().readValue(ec.getData(), SocialClientUserDetails.class);
+                user = JsonUtils.readValue(ec.getData(), SocialClientUserDetails.class);
             }
-        } catch (IOException x) {
+        } catch (JsonUtils.JsonUtilException x) {
             throw new BadCredentialsException("JsonConversion error", x);
         }
 
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/DescribedApproval.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/DescribedApproval.java
index 0f5922bdf4e..0320c67ac93 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/DescribedApproval.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/DescribedApproval.java
@@ -13,8 +13,8 @@
 package org.cloudfoundry.identity.uaa.login;
 
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.codehaus.jackson.annotate.JsonIgnore;
 
 public class DescribedApproval extends Approval {
     private String description;
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationService.java
index 51667378f84..61e7ef31db0 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationService.java
@@ -1,5 +1,6 @@
 package org.cloudfoundry.identity.uaa.login;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
@@ -9,11 +10,10 @@
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
 import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceAlreadyExistsException;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.oauth2.provider.ClientDetails;
 import org.springframework.security.oauth2.provider.ClientDetailsService;
@@ -42,10 +42,8 @@ public class EmailAccountCreationService implements AccountCreationService {
     private final ClientDetailsService clientDetailsService;
     private final String brand;
     private final UaaUrlUtils uaaUrlUtils;
-    private final ObjectMapper objectMapper;
 
     public EmailAccountCreationService(
-        ObjectMapper objectMapper,
         SpringTemplateEngine templateEngine,
         MessageService messageService,
         ExpiringCodeStore codeStore,
@@ -54,7 +52,6 @@ public EmailAccountCreationService(
         UaaUrlUtils uaaUrlUtils,
         String brand) {
 
-        this.objectMapper = objectMapper;
         this.templateEngine = templateEngine;
         this.messageService = messageService;
         this.codeStore= codeStore;
@@ -103,7 +100,7 @@ private ExpiringCode getExpiringCode(String userId, String clientId, Timestamp e
         Map<String, String> codeData = new HashMap<>();
         codeData.put("user_id", userId);
         codeData.put("client_id", clientId);
-        String codeDataString = objectMapper.writeValueAsString(codeData);
+        String codeDataString = JsonUtils.writeValueAsString(codeData);
         return new ExpiringCode(null, expiresAt, codeDataString);
     }
 
@@ -116,7 +113,7 @@ public AccountCreationResponse completeActivation(String code) throws IOExceptio
             throw new HttpClientErrorException(HttpStatus.BAD_REQUEST);
         }
 
-        Map<String, String> data = objectMapper.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
+        Map<String, String> data = JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
         ScimUser user = scimUserProvisioning.retrieve(data.get("user_id"));
         user = scimUserProvisioning.verifyUser(user.getId(), user.getVersion());
 
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailInvitationsService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailInvitationsService.java
index 288febf317c..5050af807ac 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailInvitationsService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailInvitationsService.java
@@ -8,15 +8,13 @@
 import org.cloudfoundry.identity.uaa.oauth.ClientAdminEndpoints;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
 import org.springframework.security.oauth2.provider.ClientDetails;
-import org.springframework.security.oauth2.provider.client.BaseClientDetails;
 import org.springframework.stereotype.Service;
 import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestTemplate;
 import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
 import org.thymeleaf.context.Context;
 import org.thymeleaf.spring4.SpringTemplateEngine;
@@ -97,7 +95,7 @@ public void inviteUser(String email, String currentUser) {
         } catch (HttpClientErrorException e) {
             String uaaResponse = e.getResponseBodyAsString();
             try {
-                ExistingUserResponse existingUserResponse = new ObjectMapper().readValue(uaaResponse, ExistingUserResponse.class);
+                ExistingUserResponse existingUserResponse = JsonUtils.readValue(uaaResponse, ExistingUserResponse.class);
                 if (existingUserResponse.getVerified()) {
                     throw new UaaException(e.getStatusText(), e.getStatusCode().value());
                 }
@@ -106,6 +104,8 @@ public void inviteUser(String email, String currentUser) {
                 data.put("email", email);
                 String code = expiringCodeService.generateCode(data, INVITATION_EXPIRY_DAYS, TimeUnit.DAYS);
                 sendInvitationEmail(email, existingUserResponse.getUserId(), currentUser, code);
+            } catch (JsonUtils.JsonUtilException ioe) {
+                logger.warn("couldn't invite user",ioe);
             } catch (IOException ioe) {
             	logger.warn("couldn't invite user",ioe);
             }
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordService.java
index af90c828a37..7ab0c5a47cf 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,15 +12,15 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.error.UaaException;
 import org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.util.StringUtils;
@@ -71,10 +71,10 @@ public void forgotPassword(String email) {
             if (e.getStatusCode() == HttpStatus.CONFLICT) {
                 htmlContent = getResetUnavailableEmailHtml(email);
                 try {
-                    Map<String, String> body = new ObjectMapper().readValue(e.getResponseBodyAsString(), new TypeReference<Map<String, String>>() {
+                    Map<String, String> body = JsonUtils.readValue(e.getResponseBodyAsString(), new TypeReference<Map<String, String>>() {
                     });
                     userId = body.get("user_id");
-                } catch (IOException ioe) {
+                } catch (JsonUtils.JsonUtilException ioe) {
                     logger.error("Bad response from UAA", ioe);
                 }
 
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/LoginUaaApprovalsService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/LoginUaaApprovalsService.java
index a4ced9ac16c..6622ce41538 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/LoginUaaApprovalsService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/LoginUaaApprovalsService.java
@@ -12,27 +12,17 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.login;
 
+import org.cloudfoundry.identity.uaa.authentication.Origin;
+import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
+import org.cloudfoundry.identity.uaa.oauth.approval.ApprovalsControllerService;
+import org.springframework.beans.factory.annotation.Autowired;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-
-import javassist.runtime.Desc;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.cloudfoundry.identity.uaa.authentication.Origin;
-import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.cloudfoundry.identity.uaa.oauth.approval.ApprovalsAdminEndpoints;
-import org.cloudfoundry.identity.uaa.oauth.approval.ApprovalsControllerService;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.client.RestOperations;
 
 public class LoginUaaApprovalsService implements ApprovalsService {
 
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/RestUaaApprovalsService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/RestUaaApprovalsService.java
index 81eb6fe409c..ef37632e853 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/RestUaaApprovalsService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/RestUaaApprovalsService.java
@@ -16,7 +16,6 @@
 import org.apache.commons.logging.LogFactory;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.codehaus.jackson.annotate.JsonIgnore;
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaExpiringCodeService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaExpiringCodeService.java
index e0904cebc16..ba758400864 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaExpiringCodeService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaExpiringCodeService.java
@@ -1,19 +1,16 @@
 package org.cloudfoundry.identity.uaa.login;
 
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
+import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
+import org.springframework.stereotype.Component;
+
 import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
-import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
-import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
-
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.RestTemplate;
-
 @Component
 public class UaaExpiringCodeService implements ExpiringCodeService {
     
@@ -26,7 +23,7 @@ public UaaExpiringCodeService(ExpiringCodeStore codeStore) {
     @Override
     public String generateCode(Object data, int expiryTime, TimeUnit timeUnit) throws IOException {
         Timestamp expiry = new Timestamp(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(expiryTime, timeUnit));
-        String dataJsonString = new ObjectMapper().writeValueAsString(data);
+        String dataJsonString = JsonUtils.writeValueAsString(data);
         return codeStore.generateCode(dataJsonString, expiry).getCode();
     }
 
@@ -37,8 +34,8 @@ public <T> T verifyCode(Class<T> clazz, String code) throws IOException, CodeNot
             if (code==null || expiringCode==null) {
                 throw new CodeNotFoundException();
             }
-            return new ObjectMapper().readValue(expiringCode.getData(), clazz);
-        } catch (IOException e) {
+            return JsonUtils.readValue(expiringCode.getData(), clazz);
+        } catch (JsonUtils.JsonUtilException e) {
             throw new CodeNotFoundException();
         }
     }
@@ -50,8 +47,9 @@ public Map<String,String> verifyCode(String code) throws IOException, CodeNotFou
             if (expiringCode==null) {
                 throw new CodeNotFoundException();
             }
-            return new ObjectMapper().readValue(expiringCode.getData(), new TypeReference<Map<String,String>>() {});
-        } catch (IOException e) {
+            return JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {
+            });
+        } catch (JsonUtils.JsonUtilException e) {
             throw new CodeNotFoundException();
         }
     }
diff --git a/login/src/main/resources/login-ui.xml b/login/src/main/resources/login-ui.xml
index 9fa70c18a9d..e3d326deaae 100644
--- a/login/src/main/resources/login-ui.xml
+++ b/login/src/main/resources/login-ui.xml
@@ -309,7 +309,7 @@
             </list>
         </property>
         <property name="defaultViews">
-            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
+            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                 <property name="extractValueFromSingleKeyModel" value="true" />
             </bean>
         </property>
@@ -341,9 +341,6 @@
     </bean>
 
     <bean id="accountCreationService" class="org.cloudfoundry.identity.uaa.login.EmailAccountCreationService">
-        <constructor-arg>
-            <bean class="org.codehaus.jackson.map.ObjectMapper"/>
-        </constructor-arg>
         <constructor-arg ref="mailTemplateEngine"/>
         <constructor-arg ref="messageService"/>
         <constructor-arg ref="codeStore"/>
diff --git a/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationServiceTests.java b/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationServiceTests.java
index 80f7d9d74d2..2578682401b 100644
--- a/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationServiceTests.java
+++ b/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailAccountCreationServiceTests.java
@@ -26,10 +26,10 @@
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
 import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceAlreadyExistsException;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
@@ -76,7 +76,6 @@ public void setUp() throws Exception {
         clientDetailsService = mock(ClientDetailsService.class);
         details = mock(ClientDetails.class);
         emailAccountCreationService = new EmailAccountCreationService(
-            new ObjectMapper(),
             templateEngine,
             messageService,
             codeStore,
@@ -144,7 +143,6 @@ public void testBeginActivationInOtherZone() throws Exception {
     @Test
     public void testBeginActivationWithOssBrand() throws Exception {
         emailAccountCreationService = new EmailAccountCreationService(
-            new ObjectMapper(),
             templateEngine,
             messageService,
             codeStore,
@@ -304,7 +302,7 @@ private void setUpForSuccess() throws Exception {
         Map<String,Object> data = new HashMap<>();
         data.put("user_id","newly-created-user-id");
         data.put("client_id", "login");
-        code = new ExpiringCode("the_secret_code", ts, new ObjectMapper().writeValueAsString(data));
+        code = new ExpiringCode("the_secret_code", ts, JsonUtils.writeValueAsString(data));
 
         Map<String, Object> additionalInfo = new HashMap<>();
         additionalInfo.put(EmailAccountCreationService.SIGNUP_REDIRECT_URL, "http://example.com/redirect");
diff --git a/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordServiceTests.java b/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordServiceTests.java
index 8c795cd7eb8..588b4f3f3cd 100644
--- a/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordServiceTests.java
+++ b/login/src/test/java/org/cloudfoundry/identity/uaa/login/EmailResetPasswordServiceTests.java
@@ -38,7 +38,6 @@
 import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
@@ -79,7 +78,7 @@ public void setUp() throws Exception {
         messageService = mock(EmailService.class);
         scimUserProvisioning = mock(ScimUserProvisioning.class);
         codeStore = mock(ExpiringCodeStore.class);
-        passwordResetEndpoints = new PasswordResetEndpoints(new ObjectMapper(), scimUserProvisioning, codeStore);
+        passwordResetEndpoints = new PasswordResetEndpoints(scimUserProvisioning, codeStore);
         uaaUrlUtils = new UaaUrlUtils("http://uaa.example.com/uaa");
         emailResetPasswordService = new EmailResetPasswordService(templateEngine, messageService, passwordResetEndpoints, uaaUrlUtils, "pivotal");
     }
diff --git a/login/src/test/java/org/cloudfoundry/identity/uaa/login/test/MockMvcTestClient.java b/login/src/test/java/org/cloudfoundry/identity/uaa/login/test/MockMvcTestClient.java
index 309f45eef66..43d53011df8 100644
--- a/login/src/test/java/org/cloudfoundry/identity/uaa/login/test/MockMvcTestClient.java
+++ b/login/src/test/java/org/cloudfoundry/identity/uaa/login/test/MockMvcTestClient.java
@@ -15,10 +15,10 @@
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.commons.codec.binary.Base64;
-import org.codehaus.jackson.annotate.JsonIgnoreProperties;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
@@ -31,11 +31,9 @@ public class MockMvcTestClient {
 
     //TODO - nullify?
     private MockMvc mockMvc;
-    private final ObjectMapper objectMapper;
 
     public MockMvcTestClient(MockMvc mockMvc) {
         this.mockMvc = mockMvc;
-        objectMapper = new ObjectMapper();
     }
 
     public String getOAuthAccessToken(String username, String password, String grantType, String scope)
@@ -48,7 +46,7 @@ public String getOAuthAccessToken(String username, String password, String grant
                         .param("client_id", username)
                         .param("scope", scope);
         MvcResult result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        OAuthToken oauthToken = objectMapper.readValue(result.getResponse().getContentAsByteArray(), OAuthToken.class);
+        OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), OAuthToken.class);
         return oauthToken.accessToken;
     }
 
diff --git a/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml b/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
index 20d8fa6b1ea..4e397a54845 100755
--- a/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<!-- Cloud Foundry 2012.02.03 Beta Copyright (c) [2009-2012] VMware, Inc. All Rights Reserved. This product is licensed to 
-	you under the Apache License, Version 2.0 (the "License"). You may not use this product except in compliance with the License. 
-	This product includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents 
+<!-- Cloud Foundry 2012.02.03 Beta Copyright (c) [2009-2012] VMware, Inc. All Rights Reserved. This product is licensed to
+	you under the Apache License, Version 2.0 (the "License"). You may not use this product except in compliance with the License.
+	This product includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents
 	is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. -->
 
 <beans xmlns="http://www.springframework.org/schema/beans"
@@ -92,7 +92,7 @@
 			</bean>
 		</property>
 		<property name="defaultViews">
-			<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
+			<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
 		</property>
 	</bean>
 
diff --git a/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml b/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
index 79110c9434e..88b41d9cad2 100755
--- a/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<!-- Cloud Foundry 2012.02.03 Beta Copyright (c) [2009-2012] VMware, Inc. All Rights Reserved. This product is licensed to 
-	you under the Apache License, Version 2.0 (the "License"). You may not use this product except in compliance with the License. 
-	This product includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents 
+<!-- Cloud Foundry 2012.02.03 Beta Copyright (c) [2009-2012] VMware, Inc. All Rights Reserved. This product is licensed to
+	you under the Apache License, Version 2.0 (the "License"). You may not use this product except in compliance with the License.
+	This product includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents
 	is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. -->
 
 <beans xmlns="http://www.springframework.org/schema/beans"
@@ -93,7 +93,7 @@
 			</map>
 		</property>
 		<property name="defaultViews">
-			<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
+			<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
 		</property>
 	</bean>
 
diff --git a/samples/oauth-showcase/build.gradle b/samples/oauth-showcase/build.gradle
index ab17af9255b..b11c7e32a0c 100644
--- a/samples/oauth-showcase/build.gradle
+++ b/samples/oauth-showcase/build.gradle
@@ -41,7 +41,7 @@ configurations {
 dependencies {
     compile("org.springframework.boot:spring-boot-starter-security")
     compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
-    compile 'org.springframework.security.oauth:spring-security-oauth2:2.0.3.RELEASE'
+    compile(group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version:parent.springSecurityOAuthVersion)
     runtime 'org.apache.httpcomponents:httpclient'
     runtime("org.springframework.boot:spring-boot-starter-actuator")
     compile("org.springframework.boot:spring-boot-starter-web")
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimCore.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimCore.java
index b2dd1ad61f9..1fdd6a8bd5e 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimCore.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimCore.java
@@ -14,7 +14,7 @@
 
 import java.util.Arrays;
 
-import org.codehaus.jackson.annotate.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.springframework.util.Assert;
 
 public abstract class ScimCore {
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroup.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroup.java
index f2e2a89bf42..bc01395159e 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroup.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroup.java
@@ -12,10 +12,11 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim;
 
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
 import java.util.List;
 
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
 @JsonSerialize(using = ScimGroupJsonSerializer.class, include = JsonSerialize.Inclusion.NON_NULL)
 @JsonDeserialize(using = ScimGroupJsonDeserializer.class)
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupExternalMember.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupExternalMember.java
index e9cfb1adb21..0cc5e9fbf9f 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupExternalMember.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupExternalMember.java
@@ -12,9 +12,10 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim;
 
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class ScimGroupExternalMember extends ScimCore {
 
     private String groupId;
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonDeserializer.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonDeserializer.java
index fe6729a3613..912998e3dfb 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonDeserializer.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonDeserializer.java
@@ -12,6 +12,12 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim;
 
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -21,17 +27,11 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
-
 public class ScimGroupJsonDeserializer extends JsonDeserializer<ScimGroup> {
 
     @Override
     public ScimGroup deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
         ScimGroup group = new ScimGroup();
 
         Map<ScimGroupMember.Role, List<ScimGroupMember>> roles = new HashMap<ScimGroupMember.Role, List<ScimGroupMember>>();
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonSerializer.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonSerializer.java
index d8d97840fc2..ddcc1819999 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonSerializer.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupJsonSerializer.java
@@ -12,6 +12,11 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim;
 
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -19,15 +24,11 @@
 import java.util.List;
 import java.util.Map;
 
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.map.JsonSerializer;
-import org.codehaus.jackson.map.SerializerProvider;
 
 public class ScimGroupJsonSerializer extends JsonSerializer<ScimGroup> {
     @Override
     public void serialize(ScimGroup group, JsonGenerator jgen, SerializerProvider provider) throws IOException,
-                    JsonProcessingException {
+        JsonProcessingException {
         Map<String, List<ScimGroupMember>> roles = new HashMap<String, List<ScimGroupMember>>();
         for (ScimGroupMember.Role authority : ScimGroupMember.Role.values()) {
             String role = authority.toString().toLowerCase() + "s";
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupMember.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupMember.java
index a410c7cb6e2..3147056d26c 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupMember.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimGroupMember.java
@@ -15,15 +15,15 @@
 import java.util.Arrays;
 import java.util.List;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class ScimGroupMember {
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public static enum Role {
         MEMBER, READER, WRITER;
     }
@@ -36,7 +36,7 @@ public static enum Role {
 
     private String origin = Origin.UAA;
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public enum Type {
         USER, GROUP
     }
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimMeta.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimMeta.java
index 8da98bef046..a37d27b90c1 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimMeta.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimMeta.java
@@ -14,12 +14,13 @@
 
 import java.util.Date;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.cloudfoundry.identity.uaa.util.json.JsonDateDeserializer;
 import org.cloudfoundry.identity.uaa.util.json.JsonDateSerializer;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class ScimMeta {
     private int version = 0;
 
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUser.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUser.java
index 8d4f7979b70..ad26227ad43 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUser.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUser.java
@@ -18,11 +18,11 @@
 import java.util.List;
 import java.util.Set;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.codehaus.jackson.annotate.JsonIgnore;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.annotate.JsonDeserialize;
-import org.codehaus.jackson.map.annotate.JsonSerialize;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
@@ -35,11 +35,11 @@
  * 
  * @author Luke Taylor
  */
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 @JsonDeserialize(using = ScimUserJsonDeserializer.class)
 public final class ScimUser extends ScimCore {
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public static final class Group {
         String value;
 
@@ -129,7 +129,7 @@ public String toString() {
         }
     }
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public static final class Name {
         String formatted;
 
@@ -202,7 +202,7 @@ public void setHonorificSuffix(String honorificSuffix) {
 
     }
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_DEFAULT)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public static final class Email {
         private String value;
 
@@ -258,7 +258,7 @@ public int hashCode() {
         }
     }
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_DEFAULT)
+    @JsonInclude(JsonInclude.Include.NON_NULL)
     public static final class PhoneNumber {
         private String value;
 
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUserJsonDeserializer.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUserJsonDeserializer.java
index 45dcdf55166..eab181ffaf5 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUserJsonDeserializer.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUserJsonDeserializer.java
@@ -14,16 +14,17 @@
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.JsonProcessingException;
-import org.codehaus.jackson.JsonToken;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.exc.UnrecognizedPropertyException;
 
 public class ScimUserJsonDeserializer extends JsonDeserializer<ScimUser> {
     @Override
@@ -81,10 +82,10 @@ public ScimUser deserialize(JsonParser jp, DeserializationContext ctxt) throws I
                 } else if ("zoneId".equalsIgnoreCase(fieldName)) {
                     user.setZoneId(jp.readValueAs(String.class));
                 } else if ("approvals".equalsIgnoreCase(fieldName)) {
-                    user.setApprovals(new HashSet<Approval>(Arrays.asList(jp.readValueAs(Approval[].class))));
+                    user.setApprovals(new HashSet<>(Arrays.asList(jp.readValueAs(Approval[].class))));
                 } else {
                     throw new UnrecognizedPropertyException("unrecognized field", jp.getCurrentLocation(),
-                                    ScimUser.class, fieldName);
+                                    ScimUser.class, fieldName, Collections.emptySet());
                 }
             }
         }
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpoints.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpoints.java
index f4f50112d70..eddb1cbef9c 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpoints.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpoints.java
@@ -1,5 +1,7 @@
 package org.cloudfoundry.identity.uaa.scim.endpoints;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.cloudfoundry.identity.uaa.audit.event.UserModifiedEvent;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
@@ -8,9 +10,7 @@
 import org.cloudfoundry.identity.uaa.rest.QueryableResourceManager;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.ApplicationEventPublisherAware;
 import org.springframework.http.ResponseEntity;
@@ -34,17 +34,15 @@
 public class ChangeEmailEndpoints implements ApplicationEventPublisherAware {
     private final ScimUserProvisioning scimUserProvisioning;
     private final ExpiringCodeStore expiringCodeStore;
-    private final ObjectMapper objectMapper;
     private ApplicationEventPublisher publisher;
     private final QueryableResourceManager<ClientDetails> clientDetailsService;
     private static final int EMAIL_CHANGE_LIFETIME = 30 * 60 * 1000;
 
     public static final String CHANGE_EMAIL_REDIRECT_URL = "change_email_redirect_url";
 
-    public ChangeEmailEndpoints(ScimUserProvisioning scimUserProvisioning, ExpiringCodeStore expiringCodeStore, ObjectMapper objectMapper, QueryableResourceManager<ClientDetails> clientDetailsService) {
+    public ChangeEmailEndpoints(ScimUserProvisioning scimUserProvisioning, ExpiringCodeStore expiringCodeStore, QueryableResourceManager<ClientDetails> clientDetailsService) {
         this.scimUserProvisioning = scimUserProvisioning;
         this.expiringCodeStore = expiringCodeStore;
-        this.objectMapper = objectMapper;
         this.clientDetailsService = clientDetailsService;
     }
 
@@ -63,8 +61,8 @@ public ResponseEntity<String> generateEmailVerificationCode(@RequestBody EmailCh
 
         String code;
         try {
-            code = expiringCodeStore.generateCode(objectMapper.writeValueAsString(emailChange), new Timestamp(System.currentTimeMillis() + EMAIL_CHANGE_LIFETIME)).getCode();
-        } catch (IOException e) {
+            code = expiringCodeStore.generateCode(JsonUtils.writeValueAsString(emailChange), new Timestamp(System.currentTimeMillis() + EMAIL_CHANGE_LIFETIME)).getCode();
+        } catch (JsonUtils.JsonUtilException e) {
             throw new UaaException("Error while generating change email code", e);
         }
 
@@ -75,7 +73,7 @@ public ResponseEntity<String> generateEmailVerificationCode(@RequestBody EmailCh
     public ResponseEntity<EmailChangeResponse> changeEmail(@RequestBody String code) throws IOException {
         ExpiringCode expiringCode = expiringCodeStore.retrieveCode(code);
         if (expiringCode != null) {
-            Map<String, String> data = objectMapper.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
+            Map<String, String> data = JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
             String userId = data.get("userId");
             String email = data.get("email");
             ScimUser user = scimUserProvisioning.retrieve(userId);
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpoints.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpoints.java
index 716fe2f05cb..2f779992848 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpoints.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpoints.java
@@ -12,6 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim.endpoints;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
@@ -24,8 +25,6 @@
 import org.cloudfoundry.identity.uaa.user.UaaUser;
 import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.JsonUtils.JsonUtilException;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.springframework.context.ApplicationEvent;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.ApplicationEventPublisherAware;
@@ -51,7 +50,6 @@
 import static org.springframework.http.HttpStatus.NOT_FOUND;
 import static org.springframework.http.HttpStatus.OK;
 import static org.springframework.http.HttpStatus.UNAUTHORIZED;
-import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
 
 @Controller
 public class PasswordResetEndpoints implements ApplicationEventPublisherAware {
@@ -59,11 +57,9 @@ public class PasswordResetEndpoints implements ApplicationEventPublisherAware {
     public static final int PASSWORD_RESET_LIFETIME = 30 * 60 * 1000;
     private final ScimUserProvisioning scimUserProvisioning;
     private final ExpiringCodeStore expiringCodeStore;
-    private final ObjectMapper objectMapper;
     private ApplicationEventPublisher publisher;
 
-    public PasswordResetEndpoints(ObjectMapper objectMapper, ScimUserProvisioning scimUserProvisioning, ExpiringCodeStore expiringCodeStore) {
-        this.objectMapper = objectMapper;
+    public PasswordResetEndpoints(ScimUserProvisioning scimUserProvisioning, ExpiringCodeStore expiringCodeStore) {
         this.scimUserProvisioning = scimUserProvisioning;
         this.expiringCodeStore = expiringCodeStore;
     }
@@ -75,7 +71,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
 
     @RequestMapping(value = "/password_resets", method = RequestMethod.POST)
     public ResponseEntity<Map<String,String>> resetPassword(@RequestBody String email) throws IOException {
-        String jsonEmail = objectMapper.writeValueAsString(email);
+        String jsonEmail = JsonUtils.writeValueAsString(email);
         Map<String,String> response = new HashMap<>();
         List<ScimUser> results = scimUserProvisioning.query("userName eq " + jsonEmail + " and origin eq \"" + Origin.UAA + "\"");
         if (results.isEmpty()) {
diff --git a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordScore.java b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordScore.java
index 68a556bb399..4b1f8e0fa53 100644
--- a/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordScore.java
+++ b/scim/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordScore.java
@@ -13,9 +13,9 @@
 
 package org.cloudfoundry.identity.uaa.scim.endpoints;
 
-import org.codehaus.jackson.map.annotate.JsonSerialize;
+import com.fasterxml.jackson.annotation.JsonInclude;
 
-@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class PasswordScore {
     private int score;
     private int requiredScore;
diff --git a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimUserTests.java b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimUserTests.java
index 6ba405cc7fd..904680b19a2 100644
--- a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimUserTests.java
+++ b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimUserTests.java
@@ -30,7 +30,7 @@
 
 import org.cloudfoundry.identity.uaa.oauth.approval.Approval;
 import org.cloudfoundry.identity.uaa.scim.ScimUser.Group;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -40,7 +40,6 @@
  * @author Luke Taylor
  */
 public class ScimUserTests {
-    ObjectMapper mapper = new ObjectMapper();
 
     private static final String SCHEMAS = "\"schemas\": [\"urn:scim:schemas:core:1.0\"],";
 
@@ -50,7 +49,7 @@ public void minimalJsonMapsToUser() throws Exception {
                         "  \"userName\": \"bjensen@example.com\"\n" +
                         "}";
 
-        ScimUser user = mapper.readValue(minimal, ScimUser.class);
+        ScimUser user = JsonUtils.readValue(minimal, ScimUser.class);
         assertEquals("bjensen@example.com", user.getUserName());
         assertEquals(null, user.getPassword());
     }
@@ -62,7 +61,7 @@ public void passwordJsonMapsToUser() throws Exception {
                         "  \"password\": \"foo\"\n" +
                         "}";
 
-        ScimUser user = mapper.readValue(minimal, ScimUser.class);
+        ScimUser user = JsonUtils.readValue(minimal, ScimUser.class);
         assertEquals("foo", user.getPassword());
     }
 
@@ -73,7 +72,7 @@ public void minimalUserMapsToJson() throws Exception {
         user.setUserName("joe");
         user.getMeta().setCreated(new SimpleDateFormat("yyyy-MM-dd").parse("2011-11-30"));
 
-        String json = mapper.writeValueAsString(user);
+        String json = JsonUtils.writeValueAsString(user);
         // System.err.println(json);
         assertTrue(json.contains("\"userName\":\"joe\""));
         assertTrue(json.contains("\"id\":\"123\""));
@@ -93,7 +92,7 @@ public void anotherUserMapsToJson() throws Exception {
         user.addEmail("joe@test.org");
         user.addPhoneNumber("+1-222-1234567");
 
-        String json = mapper.writeValueAsString(user);
+        String json = JsonUtils.writeValueAsString(user);
         // System.err.println(json);
         assertTrue(json.contains("\"emails\":"));
         assertTrue(json.contains("\"phoneNumbers\":"));
@@ -107,7 +106,7 @@ public void userWithGroupsMapsToJson() throws Exception {
         user.setUserName("joe");
         user.setGroups(Collections.singleton(new Group(null, "foo")));
 
-        String json = mapper.writeValueAsString(user);
+        String json = JsonUtils.writeValueAsString(user);
         // System.err.println(json);
         assertTrue(json.contains("\"groups\":"));
     }
@@ -121,7 +120,7 @@ public void emailsAreMappedCorrectly() throws Exception {
                         "{\"value\": \"babs@jensen.org\",\"type\": \"home\"}" +
                         "],\n" +
                         "\"schemas\":[\"urn:scim:schemas:core:1.0\"]}";
-        ScimUser user = mapper.readValue(json, ScimUser.class);
+        ScimUser user = JsonUtils.readValue(json, ScimUser.class);
         assertEquals(3, user.getEmails().size());
         assertEquals("bjensen@example.com", user.getEmails().get(1).getValue());
         assertEquals("babs@jensen.org", user.getEmails().get(2).getValue());
@@ -138,7 +137,7 @@ public void groupsAreMappedCorrectly() throws Exception {
                         "{\"value\": \"123456\",\"display\": \"dash.admin\"}" +
                         "],\n" +
                         "\"schemas\":[\"urn:scim:schemas:core:1.0\"]}";
-        ScimUser user = mapper.readValue(json, ScimUser.class);
+        ScimUser user = JsonUtils.readValue(json, ScimUser.class);
         assertEquals(2, user.getGroups().size());
         // System.out.println(mapper.writeValueAsString(user));
     }
@@ -147,7 +146,7 @@ public void groupsAreMappedCorrectly() throws Exception {
     public void datesAreMappedCorrectly() throws Exception {
         String json = "{ \"userName\":\"bjensen\"," +
                         "\"meta\":{\"version\":10,\"created\":\"2011-11-30T10:46:16.475Z\"}}";
-        ScimUser user = mapper.readValue(json, ScimUser.class);
+        ScimUser user = JsonUtils.readValue(json, ScimUser.class);
         assertEquals(10, user.getVersion());
         assertEquals("2011-11-30", new SimpleDateFormat("yyyy-MM-dd").format(user.getMeta().getCreated()));
         // System.out.println(mapper.writeValueAsString(user));
diff --git a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpointsTest.java b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpointsTest.java
index 29676281aab..e004df8a36d 100644
--- a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpointsTest.java
+++ b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ChangeEmailEndpointsTest.java
@@ -8,7 +8,6 @@
 import org.cloudfoundry.identity.uaa.rest.QueryableResourceManager;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -52,7 +51,7 @@ public void setUp() throws Exception {
         expiringCodeStore = Mockito.mock(ExpiringCodeStore.class);
         publisher = Mockito.mock(ApplicationEventPublisher.class);
         clientDetailsService = Mockito.mock(QueryableResourceManager.class);
-        ChangeEmailEndpoints changeEmailEndpoints = new ChangeEmailEndpoints(scimUserProvisioning, expiringCodeStore, new ObjectMapper(), clientDetailsService);
+        ChangeEmailEndpoints changeEmailEndpoints = new ChangeEmailEndpoints(scimUserProvisioning, expiringCodeStore, clientDetailsService);
         changeEmailEndpoints.setApplicationEventPublisher(publisher);
         mockMvc = MockMvcBuilders.standaloneSetup(changeEmailEndpoints).build();
     }
diff --git a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsTest.java b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsTest.java
index 5d1701f261f..1fe878639b8 100644
--- a/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsTest.java
+++ b/scim/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsTest.java
@@ -22,7 +22,6 @@
 import org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints.PasswordChange;
 import org.cloudfoundry.identity.uaa.test.MockAuthentication;
 import org.cloudfoundry.identity.uaa.util.JsonUtils;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -55,7 +54,7 @@ public class PasswordResetEndpointsTest extends TestClassNullifier {
     public void setUp() throws Exception {
         scimUserProvisioning = Mockito.mock(ScimUserProvisioning.class);
         expiringCodeStore = Mockito.mock(ExpiringCodeStore.class);
-        PasswordResetEndpoints controller = new PasswordResetEndpoints(new ObjectMapper(), scimUserProvisioning, expiringCodeStore);
+        PasswordResetEndpoints controller = new PasswordResetEndpoints(scimUserProvisioning, expiringCodeStore);
         mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
 
         Mockito.when(expiringCodeStore.generateCode(eq("id001"), any(Timestamp.class)))
diff --git a/shared_versions.gradle b/shared_versions.gradle
index 08067038551..52338d51d01 100644
--- a/shared_versions.gradle
+++ b/shared_versions.gradle
@@ -1,8 +1,12 @@
 ext {
-  springVersion = '4.0.8.RELEASE'
-  springSecurityVersion = '3.2.4.RELEASE'
-  springSecurityOAuthVersion = '2.0.3.RELEASE'
+  springVersion = '4.1.6.RELEASE'
+  springSecurityVersion = '3.2.7.RELEASE'
+  springSecurityOAuthVersion = '2.0.7.RELEASE'
   springSecurityLdapVersion = '1.3.2.RELEASE'
   postgresqlVersion = '9.1-901.jdbc3'
   tomcatVersion = '7.0.54'
+  springSecurityJwtVersion = '1.0.3.RELEASE'
+  bcpkixVersion  = '1.47'
+  apacheLdapApiVersion = '1.0.0-M22'
+  jacksonVersion = '2.5.3'
 }
diff --git a/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml b/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
index 23527ffa037..19e8913c028 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
@@ -186,10 +186,7 @@
         <constructor-arg ref="dataSource" />
     </bean>
 
-    <bean id="objectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
-
     <bean id="passwordResetEndpoints" class="org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints">
-        <constructor-arg ref="objectMapper"/>
         <constructor-arg ref="scimUserProvisioning"/>
         <constructor-arg ref="codeStore"/>
     </bean>
@@ -197,7 +194,6 @@
     <bean id="changeEmailEndpoints" class="org.cloudfoundry.identity.uaa.scim.endpoints.ChangeEmailEndpoints">
         <constructor-arg ref="scimUserProvisioning"/>
         <constructor-arg ref="codeStore"/>
-        <constructor-arg ref="objectMapper"/>
         <constructor-arg ref="clientDetailsService"/>
     </bean>
 
diff --git a/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
index 14218da6250..49ad5fd29b5 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
@@ -29,6 +29,8 @@
     <!--</bean>-->
     <bean id="oauth2RequestValidator" class="org.cloudfoundry.identity.uaa.oauth.token.UaaOauth2RequestValidator"/>
 
+    <bean id="tokenEndpointPostProcessor" class="org.cloudfoundry.identity.uaa.security.web.TokenEndpointPostProcessor"/>
+
     <oauth:authorization-server client-details-service-ref="jdbcClientDetailsService"
         token-services-ref="tokenServices" user-approval-handler-ref="userManagedApprovalHandler"
         authorization-request-manager-ref="authorizationRequestManager" request-validator-ref="oauth2RequestValidator">
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/ScimUserEndpointsIntegrationTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/ScimUserEndpointsIntegrationTests.java
index 3d5625536cf..0652a4439cf 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/ScimUserEndpointsIntegrationTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/ScimUserEndpointsIntegrationTests.java
@@ -29,7 +29,7 @@
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.test.TestAccountSetup;
 import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
@@ -293,9 +293,8 @@ public void updateUserWithBadAttributeFails() throws Exception {
         ScimUser joe = created.getBody();
         HttpHeaders headers = new HttpHeaders();
         headers.add("If-Match", "\"" + joe.getVersion() + "\"");
-        ObjectMapper mapper = new ObjectMapper();
-        Map<String, Object> map = new HashMap<String, Object>(mapper.readValue(mapper.writeValueAsString(joe),
-                        Map.class));
+        Map<String, Object> map = new HashMap<String, Object>(JsonUtils.readValue(JsonUtils.writeValueAsString(joe),
+            Map.class));
         map.put("nottheusername", JOE + "0");
         ResponseEntity<Map> response = client.exchange(serverRunning.getUrl(userEndpoint) + "/{id}", HttpMethod.PUT,
             new HttpEntity<Map>(map, headers), Map.class, joe.getId());
@@ -313,8 +312,7 @@ public void testJsonCaseInsensitivity() throws Exception {
         ScimUser joe = created.getBody();
         HttpHeaders headers = new HttpHeaders();
         headers.add("If-Match", "\"" + joe.getVersion() + "\"");
-        ObjectMapper mapper = new ObjectMapper();
-        Map<String, Object> map = new HashMap<String, Object>(mapper.readValue(mapper.writeValueAsString(joe),
+        Map<String, Object> map = new HashMap<String, Object>(JsonUtils.readValue(JsonUtils.writeValueAsString(joe),
                         Map.class));
         map.put("username", JOE + "0");
         map.remove("userName");
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ImplicitGrantIT.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ImplicitGrantIT.java
index 43a18560367..19d0a017a2f 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ImplicitGrantIT.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ImplicitGrantIT.java
@@ -21,8 +21,9 @@
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isEmptyOrNullString;
 import static org.hamcrest.Matchers.not;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Rule;
@@ -115,7 +116,7 @@ public void testDefaultScopes() throws Exception {
 
         Jwt access_token = JwtHelper.decode(params.getFirst("access_token"));
 
-        Map<String, Object> claims = new ObjectMapper().readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {
+        Map<String, Object> claims = JsonUtils.readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {
         });
 
         Assert.assertThat((String) claims.get("jti"), is(params.getFirst("jti")));
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/OpenIdTokenGrantsIT.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/OpenIdTokenGrantsIT.java
index 4a25d952626..7dfb5a3de0a 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/OpenIdTokenGrantsIT.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/OpenIdTokenGrantsIT.java
@@ -12,27 +12,11 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.integration.feature;
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.codec.binary.Base64;
-import org.apache.http.client.HttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
 import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
@@ -48,16 +32,11 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
-import org.springframework.security.oauth2.client.OAuth2RestTemplate;
-import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
 import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
 import org.springframework.security.oauth2.client.test.TestAccounts;
 import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
-import org.springframework.security.oauth2.common.AuthenticationScheme;
 import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -69,6 +48,20 @@
 import org.springframework.web.util.UriComponentsBuilder;
 import org.springframework.web.util.UriUtils;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(classes = DefaultIntegrationTestConfig.class)
 @OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
@@ -170,7 +163,7 @@ public void testImplicitGrant() throws Exception {
     private void validateToken(String paramName, Map params, String[] scopes) throws java.io.IOException {
         Jwt access_token = JwtHelper.decode((String)params.get(paramName));
 
-        Map<String, Object> claims = new ObjectMapper().readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {
+        Map<String, Object> claims = JsonUtils.readValue(access_token.getClaims(), new TypeReference<Map<String, Object>>() {
         });
 
         Assert.assertThat((String) claims.get("jti"), is(params.get("jti")));
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/util/IntegrationTestUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/util/IntegrationTestUtils.java
index 3dc60f58c60..63259cc49bf 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/util/IntegrationTestUtils.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/util/IntegrationTestUtils.java
@@ -14,6 +14,7 @@
 
 package org.cloudfoundry.identity.uaa.integration.util;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.http.client.HttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.cloudfoundry.identity.uaa.ServerRunning;
@@ -25,7 +26,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.Assert;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
index 828463abe3f..ed67ec27b17 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
@@ -11,9 +11,9 @@
 import org.cloudfoundry.identity.uaa.login.test.MockMvcTestClient;
 import org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.SetServerNameRequestPostProcessor;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -253,7 +253,7 @@ public void testCreatingAnAccountInAnotherZoneWithNoClientRedirect() throws Exce
         mockMvc.perform(post("/identity-zones")
                 .header("Authorization", "Bearer " + zonesCreateToken)
                 .contentType(MediaType.APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(identityZone)))
+                .content(JsonUtils.writeValueAsString(identityZone)))
                 .andExpect(status().isCreated());
 
         mockMvc.perform(post("/create_account.do")
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
index 9610cfadfaa..1cc761ffa2b 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
@@ -12,7 +12,7 @@
 import org.cloudfoundry.identity.uaa.oauth.RemoteUserAuthentication;
 import org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher;
 import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -132,11 +132,11 @@ public void testLoginUsingPasscodeWithSamlToken() throws Exception {
             .accept(APPLICATION_JSON)
             .session(session);
 
-        String passcode = new ObjectMapper().readValue(
+        String passcode = JsonUtils.readValue(
             mockMvc.perform(get)
-            .andExpect(status().isOk())
-            .andDo(print())
-            .andReturn().getResponse().getContentAsString(),
+                .andExpect(status().isOk())
+                .andDo(print())
+                .andReturn().getResponse().getContentAsString(),
             String.class);
 
         mockSecurityContext.setAuthentication(null);
@@ -158,7 +158,7 @@ public void testLoginUsingPasscodeWithSamlToken() throws Exception {
 
 
         Map accessToken =
-            new ObjectMapper().readValue(
+            JsonUtils.readValue(
                 mockMvc.perform(post)
                     .andDo(print())
                     .andExpect(status().isOk())
@@ -199,7 +199,7 @@ public void testLoginUsingPasscodeWithUaaToken() throws Exception {
             .accept(APPLICATION_JSON)
             .session(session);
 
-        String passcode = new ObjectMapper().readValue(
+        String passcode = JsonUtils.readValue(
             mockMvc.perform(get)
                 .andExpect(status().isOk())
                 .andDo(print())
@@ -225,7 +225,7 @@ public void testLoginUsingPasscodeWithUaaToken() throws Exception {
 
 
         Map accessToken =
-            new ObjectMapper().readValue(
+            JsonUtils.readValue(
                 mockMvc.perform(post)
                     .andDo(print())
                     .andExpect(status().isOk())
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMvcMockTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMvcMockTests.java
index 57299a0c8f3..66cd8143051 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMvcMockTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMvcMockTests.java
@@ -46,7 +46,7 @@
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -428,7 +428,7 @@ public void loginServerPasswordChange() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + loginToken)
-            .content(new ObjectMapper().writeValueAsBytes(pwch));
+            .content(JsonUtils.writeValueAsBytes(pwch));
 
         mockMvc.perform(changePasswordPost)
                 .andExpect(status().isOk());
@@ -447,7 +447,7 @@ public void loginServerPasswordChange() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + loginToken)
-            .content(new ObjectMapper().writeValueAsBytes(pwch));
+            .content(JsonUtils.writeValueAsBytes(pwch));
 
         mockMvc.perform(changePasswordPost)
             .andExpect(status().isOk());
@@ -466,7 +466,7 @@ public void loginServerInvalidPasswordChange() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + loginToken)
-            .content(new ObjectMapper().writeValueAsBytes(pwch));
+            .content(JsonUtils.writeValueAsBytes(pwch));
 
         mockMvc.perform(changePasswordPost)
             .andExpect(status().isUnauthorized());
@@ -514,9 +514,11 @@ public void clientAuthenticationFailureClientNotFound() throws Exception {
             .param("client_id", "login")
             .param("scope", "oauth.login");
         mockMvc.perform(oauthTokenPost).andExpect(status().isUnauthorized());
-        verify(listener, times(1)).onApplicationEvent(captor.capture());
-        ClientAuthenticationFailureEvent event = (ClientAuthenticationFailureEvent)captor.getValue();
-        assertEquals("login", event.getClientId());
+        verify(listener, atLeast(1)).onApplicationEvent(captor.capture());
+        PrincipalAuthenticationFailureEvent event0 = (PrincipalAuthenticationFailureEvent) captor.getAllValues().get(0);
+        assertEquals("login2", event0.getAuditEvent().getPrincipalId());
+        ClientAuthenticationFailureEvent event1 = (ClientAuthenticationFailureEvent)captor.getAllValues().get(1);
+        assertEquals("login", event1.getClientId());
     }
     @Test
     public void testUserApprovalAdded() throws Exception {
@@ -529,7 +531,7 @@ public void testUserApprovalAdded() throws Exception {
                 .accept(MediaType.APPLICATION_JSON_VALUE)
                 .contentType(MediaType.APPLICATION_JSON)
                 .header("Authorization", "Bearer " + marissaToken)
-                .content(new ObjectMapper().writeValueAsBytes(approvals));
+                .content(JsonUtils.writeValueAsBytes(approvals));
 
         testListener.clearEvents();
 
@@ -559,7 +561,7 @@ public void testUserCreatedEvent() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         testListener.clearEvents();
 
@@ -630,12 +632,12 @@ public void testUserModifiedAndDeleteEvent() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         ResultActions result = mockMvc.perform(userPost)
             .andExpect(status().isCreated());
 
-        user = new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsByteArray(), ScimUser.class);
+        user = JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimUser.class);
         testListener.clearEvents();
 
         user.setName(new ScimUser.Name(modifiedFirstName, lastName));
@@ -644,7 +646,7 @@ public void testUserModifiedAndDeleteEvent() throws Exception {
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
             .header("If-Match", user.getVersion())
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         mockMvc.perform(userPut).andExpect(status().isOk());
 
@@ -690,11 +692,11 @@ public void testUserVerifiedEvent() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         ResultActions result = mockMvc.perform(userPost)
             .andExpect(status().isCreated());
-        user = new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsByteArray(), ScimUser.class);
+        user = JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimUser.class);
 
         testListener.clearEvents();
 
@@ -770,10 +772,10 @@ public void testGroupEvents() throws Exception {
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
-            .content(new ObjectMapper().writeValueAsBytes(group));
+            .content(JsonUtils.writeValueAsBytes(group));
 
         ResultActions result = mockMvc.perform(groupPost).andExpect(status().isCreated());
-        group = new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
+        group = JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
 
         assertEquals(1, testListener.getEventCount());
         assertEquals(GroupModifiedEvent.class, testListener.getLatestEvent().getClass());
@@ -781,7 +783,7 @@ public void testGroupEvents() throws Exception {
         assertEquals(AuditEventType.GroupCreatedEvent, event.getAuditEvent().getType());
         assertEquals(group.getId(), event.getAuditEvent().getPrincipalId());
         assertEquals(new GroupModifiedEvent.GroupInfo(group.getDisplayName(), ScimEventPublisher.getMembers(group)),
-            new ObjectMapper().readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
+            JsonUtils.readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
 
         //update the group with one additional member
         List<ScimGroupMember> members = group.getMembers();
@@ -792,11 +794,11 @@ public void testGroupEvents() throws Exception {
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
             .header("If-Match", group.getVersion())
-            .content(new ObjectMapper().writeValueAsBytes(group));
+            .content(JsonUtils.writeValueAsBytes(group));
 
         testListener.clearEvents();
         result = mockMvc.perform(groupPut).andExpect(status().isOk());
-        group = new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
+        group = JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
 
         assertEquals(1, testListener.getEventCount());
         assertEquals(GroupModifiedEvent.class, testListener.getLatestEvent().getClass());
@@ -804,7 +806,7 @@ public void testGroupEvents() throws Exception {
         assertEquals(AuditEventType.GroupModifiedEvent, event.getAuditEvent().getType());
         assertEquals(group.getId(), event.getAuditEvent().getPrincipalId());
         assertEquals(new GroupModifiedEvent.GroupInfo(group.getDisplayName(), ScimEventPublisher.getMembers(group)),
-            new ObjectMapper().readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
+            JsonUtils.readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
 
 
         //delete the group
@@ -813,11 +815,11 @@ public void testGroupEvents() throws Exception {
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
             .header("If-Match", group.getVersion())
-            .content(new ObjectMapper().writeValueAsBytes(group));
+            .content(JsonUtils.writeValueAsBytes(group));
 
         testListener.clearEvents();
         result = mockMvc.perform(groupDelete).andExpect(status().isOk());
-        group = new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
+        group = JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimGroup.class);
 
         assertEquals(1, testListener.getEventCount());
         assertEquals(GroupModifiedEvent.class, testListener.getLatestEvent().getClass());
@@ -825,7 +827,7 @@ public void testGroupEvents() throws Exception {
         assertEquals(AuditEventType.GroupDeletedEvent, event.getAuditEvent().getType());
         assertEquals(group.getId(), event.getAuditEvent().getPrincipalId());
         assertEquals(new GroupModifiedEvent.GroupInfo(group.getDisplayName(), ScimEventPublisher.getMembers(group)),
-            new ObjectMapper().readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
+            JsonUtils.readValue(event.getAuditEvent().getData(), GroupModifiedEvent.GroupInfo.class));
 
 
     }
@@ -842,7 +844,7 @@ private ScimUser createUser(String adminToken, String username, String firstname
             .accept(MediaType.APPLICATION_JSON_VALUE)
             .contentType(MediaType.APPLICATION_JSON)
             .header("Authorization", "Bearer " + adminToken)
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         testListener.clearEvents();
 
@@ -855,7 +857,7 @@ private ScimUser createUser(String adminToken, String username, String firstname
         assertEquals(username, userModifiedEvent.getUsername());
         assertEquals(AuditEventType.UserCreatedEvent, userModifiedEvent.getAuditEvent().getType());
 
-        return new ObjectMapper().readValue(result.andReturn().getResponse().getContentAsString(), ScimUser.class);
+        return JsonUtils.readValue(result.andReturn().getResponse().getContentAsString(), ScimUser.class);
 
     }
 
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointsMockMvcTests.java
index 1809ba0588d..8c9bd7f9a67 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/clients/ClientAdminEndpointsMockMvcTests.java
@@ -1,5 +1,6 @@
 package org.cloudfoundry.identity.uaa.mock.clients;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.googlecode.flyway.core.Flyway;
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
 import org.cloudfoundry.identity.uaa.audit.AuditEventType;
@@ -26,8 +27,6 @@
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
 import org.cloudfoundry.identity.uaa.user.UaaUser;
 import org.cloudfoundry.identity.uaa.util.JsonUtils;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -1188,11 +1187,11 @@ private ClientDetailsModification[] createBaseClients(int length, String grantTy
     }
 
     private String toString(Object client) throws Exception {
-        return new ObjectMapper().writeValueAsString(client);
+        return JsonUtils.writeValueAsString(client);
     }
 
     private String toString(Object[] clients) throws Exception {
-        return new ObjectMapper().writeValueAsString(clients);
+        return JsonUtils.writeValueAsString(clients);
     }
 
     private ClientDetails clientFromString(String client) throws Exception {
@@ -1200,8 +1199,7 @@ private ClientDetails clientFromString(String client) throws Exception {
     }
 
     private Object fromString(String body, Class<?> clazz) throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        return mapper.readValue(body, clazz);
+        return JsonUtils.readValue(body, clazz);
     }
 
     private ClientDetails[] clientArrayFromString(String clients) throws Exception {
@@ -1209,8 +1207,7 @@ private ClientDetails[] clientArrayFromString(String clients) throws Exception {
     }
 
     private Object[] arrayFromString(String body, Class<?> clazz) throws Exception {
-        ObjectMapper mapper = new ObjectMapper();
-        return (Object[])mapper.readValue(body, clazz);
+        return (Object[])JsonUtils.readValue(body, clazz);
     }
 
 
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/codestore/ExpiringCodeStoreMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/codestore/ExpiringCodeStoreMockMvcTests.java
index 6d763a1af16..e66e3095910 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/codestore/ExpiringCodeStoreMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/codestore/ExpiringCodeStoreMockMvcTests.java
@@ -17,7 +17,7 @@
 import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -73,7 +73,7 @@ public void testGenerateCode() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() + 60000);
         ExpiringCode code = new ExpiringCode(null, ts, "{}");
 
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -95,7 +95,7 @@ public void testGenerateCodeWithInvalidScope() throws Exception {
         TestClient testClient = new TestClient(mockMvc);
         String loginToken = testClient.getClientCredentialsOAuthAccessToken("admin", "adminsecret", "scim.read");
 
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -111,7 +111,7 @@ public void testGenerateCodeAnonymous() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() + 60000);
         ExpiringCode code = new ExpiringCode(null, ts, "{}");
 
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .contentType(APPLICATION_JSON)
                         .accept(MediaType.APPLICATION_JSON)
@@ -125,7 +125,7 @@ public void testGenerateCodeAnonymous() throws Exception {
     public void testGenerateCodeWithNullData() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() + 60000);
         ExpiringCode code = new ExpiringCode(null, ts, null);
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -140,7 +140,7 @@ public void testGenerateCodeWithNullData() throws Exception {
     @Test
     public void testGenerateCodeWithNullExpiresAt() throws Exception {
         ExpiringCode code = new ExpiringCode(null, null, "{}");
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -156,7 +156,7 @@ public void testGenerateCodeWithNullExpiresAt() throws Exception {
     public void testGenerateCodeWithExpiresAtInThePast() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() - 60000);
         ExpiringCode code = new ExpiringCode(null, ts, null);
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -172,7 +172,7 @@ public void testGenerateCodeWithExpiresAtInThePast() throws Exception {
     public void testRetrieveCode() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() + 60000);
         ExpiringCode code = new ExpiringCode(null, ts, "{}");
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -183,7 +183,7 @@ public void testRetrieveCode() throws Exception {
                         .andExpect(status().isCreated())
                         .andReturn();
 
-        ExpiringCode rc = new ObjectMapper().readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
+        ExpiringCode rc = JsonUtils.readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
 
         MockHttpServletRequestBuilder get = get("/Codes/" + rc.getCode())
                         .header("Authorization", "Bearer " + loginToken)
@@ -193,7 +193,7 @@ public void testRetrieveCode() throws Exception {
                         .andExpect(status().isOk())
                         .andReturn();
 
-        ExpiringCode rc1 = new ObjectMapper().readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
+        ExpiringCode rc1 = JsonUtils.readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
 
         assertEquals(rc, rc1);
     }
@@ -202,7 +202,7 @@ public void testRetrieveCode() throws Exception {
     public void testRetrieveCodeThatIsExpired() throws Exception {
         Timestamp ts = new Timestamp(System.currentTimeMillis() + 1000);
         ExpiringCode code = new ExpiringCode(null, ts, "{}");
-        String requestBody = new ObjectMapper().writeValueAsString(code);
+        String requestBody = JsonUtils.writeValueAsString(code);
         MockHttpServletRequestBuilder post = post("/Codes")
                         .header("Authorization", "Bearer " + loginToken)
                         .contentType(APPLICATION_JSON)
@@ -213,7 +213,7 @@ public void testRetrieveCodeThatIsExpired() throws Exception {
                         .andExpect(status().isCreated())
                         .andReturn();
 
-        ExpiringCode rc = new ObjectMapper().readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
+        ExpiringCode rc = JsonUtils.readValue(result.getResponse().getContentAsString(), ExpiringCode.class);
         Thread.sleep(1001);
         MockHttpServletRequestBuilder get = get("/Codes/" + rc.getCode())
                         .header("Authorization", "Bearer " + loginToken)
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
index 7929318ed37..8e277ebbaaf 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
@@ -18,7 +18,7 @@
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -124,7 +124,7 @@ public void checkTokenKeyValues() throws Exception {
             .andExpect(status().isOk())
             .andReturn();
 
-        Map<String,Object> key = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Map.class);
+        Map<String,Object> key = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
 
         Object kty = key.get("kty");
         assertNotNull(kty);
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
index 6099bfd0d6d..cae04c40fbe 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
@@ -12,6 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.mock.token;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.googlecode.flyway.core.Flyway;
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
@@ -33,14 +34,13 @@
 import org.cloudfoundry.identity.uaa.user.UaaAuthority;
 import org.cloudfoundry.identity.uaa.user.UaaUser;
 import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.SetServerNameRequestPostProcessor;
 import org.cloudfoundry.identity.uaa.zone.IdentityProvider;
 import org.cloudfoundry.identity.uaa.zone.IdentityProviderProvisioning;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneProvisioning;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
@@ -692,7 +692,7 @@ public void testOpenIdToken() throws Exception {
             .param("password", SECRET)
             .param(OAuth2Utils.SCOPE, "openid");
         MvcResult result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        Map token = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(), Map.class);
+        Map token = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
         assertNotNull(token.get("access_token"));
         assertNotNull(token.get("refresh_token"));
         assertNotNull(token.get("id_token"));
@@ -761,7 +761,7 @@ public void testOpenIdToken() throws Exception {
             .param(OAuth2Utils.CLIENT_ID, clientId)
             .param(OAuth2Utils.REDIRECT_URI, TEST_REDIRECT_URI);
         result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        token = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(), Map.class);
+        token = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
         assertNotNull(token.get("access_token"));
         assertNotNull(token.get("refresh_token"));
         assertNotNull(token.get("id_token"));
@@ -889,7 +889,7 @@ private Map<String, Object> getClaimsForToken(String token) {
 
         Map<String, Object> claims = null;
         try {
-            claims = new ObjectMapper().readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
+            claims = JsonUtils.readValue(tokenJwt.getClaims(), new TypeReference<Map<String, Object>>() {
             });
         } catch (Exception e) {
             throw new IllegalStateException("Cannot read token claims", e);
@@ -1520,7 +1520,7 @@ public void testGetClientCredentialsTokenForOtherIdentityZoneFromDefaultZoneFail
         IdentityZoneHolder.clear();
         mockMvc.perform(post("http://localhost/oauth/token")
             .accept(MediaType.APPLICATION_JSON_VALUE)
-            .header("Host", subdomain + ".localhost")
+            //.header("Host", subdomain + ".localhost") - with updated Spring, this now works for request.getServerName
             .header("Authorization", "Basic "+new String(Base64.encode((clientId  + ":" + SECRET).getBytes())))
             .param("grant_type", "client_credentials")
             .param("client_id", clientId)
@@ -1670,7 +1670,7 @@ public void testGetTokenScopesNotInAuthentication() throws Exception {
             .param(OAuth2Utils.CLIENT_ID, "identity")
             .param(OAuth2Utils.REDIRECT_URI, "http://localhost/test");
         result = mockMvc.perform(authRequest).andDo(print()).andExpect(status().is2xxSuccessful()).andReturn();
-        TestClient.OAuthToken oauthToken = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(), TestClient.OAuthToken.class);
+        TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), TestClient.OAuthToken.class);
 
         OAuth2Authentication a1 = tokenServices.loadAuthentication(oauthToken.accessToken);
 
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
index f579966ea6f..c19fed6cd13 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
@@ -14,6 +14,7 @@
 
 package org.cloudfoundry.identity.uaa.mock.util;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.codec.binary.Base64;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
@@ -33,8 +34,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter;
 import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.Assert;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationEvent;
@@ -69,7 +68,6 @@
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 public class MockMvcUtils {
-    private final ObjectMapper objectMapper = new ObjectMapper();
 
     public static MockMvcUtils utils() {
         return new MockMvcUtils();
@@ -82,9 +80,9 @@ public IdentityZone createZoneUsingWebRequest(MockMvc mockMvc, String accessToke
         MvcResult result = mockMvc.perform(post("/identity-zones")
                 .header("Authorization", "Bearer " + accessToken)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(identityZone)))
+                .content(JsonUtils.writeValueAsString(identityZone)))
                 .andExpect(status().isCreated()).andReturn();
-        return new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(), IdentityZone.class);
+        return JsonUtils.readValue(result.getResponse().getContentAsString(), IdentityZone.class);
     }
 
     public static class IdentityZoneCreationResult {
@@ -123,7 +121,7 @@ public IdentityZoneCreationResult createOtherIdentityZoneAndReturnResult(String
                 .header("Authorization", "Bearer " + identityToken)
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(identityZone)))
+                .content(JsonUtils.writeValueAsString(identityZone)))
                 .andExpect(status().isCreated());
 
         // use the identity client to grant the zones.<id>.admin scope to a user
@@ -137,7 +135,7 @@ public IdentityZoneCreationResult createOtherIdentityZoneAndReturnResult(String
                 .header("Authorization", "Bearer " + identityToken)
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(group)))
+                .content(JsonUtils.writeValueAsString(group)))
                 .andExpect(status().isCreated());
 
         // use that user to create an admin client in the new zone
@@ -149,7 +147,7 @@ public IdentityZoneCreationResult createOtherIdentityZoneAndReturnResult(String
                 .header("X-Identity-Zone-Id", identityZone.getId())
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(bootstrapClient)))
+                .content(JsonUtils.writeValueAsString(bootstrapClient)))
                 .andExpect(status().isCreated());
 
         return new IdentityZoneCreationResult(identityZone, marissa, zoneAdminAuthcodeToken);
@@ -208,9 +206,9 @@ public ScimUser createUser(MockMvc mockMvc, String accessToken, ScimUser user) t
         MvcResult userResult = mockMvc.perform(post("/Users")
                 .header("Authorization", "Bearer " + accessToken)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsBytes(user)))
+                .content(JsonUtils.writeValueAsBytes(user)))
                 .andExpect(status().isCreated()).andReturn();
-        return new ObjectMapper().readValue(userResult.getResponse().getContentAsString(), ScimUser.class);
+        return JsonUtils.readValue(userResult.getResponse().getContentAsString(), ScimUser.class);
     }
 
     public ScimGroup getGroup(MockMvc mockMvc, String accessToken, String displayName) throws Exception {
@@ -230,25 +228,25 @@ public ScimGroup getGroup(MockMvc mockMvc, String accessToken, String displayNam
     }
 
     public ScimGroup createGroup(MockMvc mockMvc, String accessToken, ScimGroup group) throws Exception {
-        return new ObjectMapper().readValue(
-                mockMvc.perform(post("/Groups")
-                        .header("Authorization", "Bearer " + accessToken)
-                        .contentType(APPLICATION_JSON)
-                        .content(new ObjectMapper().writeValueAsBytes(group)))
-                        .andExpect(status().isCreated())
-                        .andReturn().getResponse().getContentAsByteArray(),
-                ScimGroup.class);
+        return JsonUtils.readValue(
+            mockMvc.perform(post("/Groups")
+                .header("Authorization", "Bearer " + accessToken)
+                .contentType(APPLICATION_JSON)
+                .content(JsonUtils.writeValueAsString(group)))
+                .andExpect(status().isCreated())
+                .andReturn().getResponse().getContentAsString(),
+            ScimGroup.class);
     }
 
     public ScimGroup updateGroup(MockMvc mockMvc, String accessToken, ScimGroup group) throws Exception {
-        return new ObjectMapper().readValue(
+        return JsonUtils.readValue(
             mockMvc.perform(put("/Groups/" + group.getId())
                 .header("If-Match", group.getVersion())
                 .header("Authorization", "Bearer " + accessToken)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsBytes(group)))
+                .content(JsonUtils.writeValueAsString(group)))
                 .andExpect(status().isOk())
-                .andReturn().getResponse().getContentAsByteArray(),
+                .andReturn().getResponse().getContentAsString(),
             ScimGroup.class);
     }
     public BaseClientDetails createClient(MockMvc mockMvc, String accessToken, BaseClientDetails clientDetails) throws Exception {
@@ -261,14 +259,14 @@ public BaseClientDetails createClient(MockMvc mockMvc, String accessToken, BaseC
                 .header("Authorization", "Bearer " + accessToken)
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(clientDetails));
+                .content(JsonUtils.writeValueAsString(clientDetails));
         if (! zone.equals(IdentityZone.getUaa())) {
             createClientPost = createClientPost.header(IdentityZoneSwitchingFilter.HEADER, zone.getId());
         }
-        return new ObjectMapper().readValue(
-                mockMvc.perform(createClientPost)
-                        .andExpect(status().isCreated())
-                        .andReturn().getResponse().getContentAsByteArray(), BaseClientDetails.class);
+        return JsonUtils.readValue(
+            mockMvc.perform(createClientPost)
+                .andExpect(status().isCreated())
+                .andReturn().getResponse().getContentAsString(), BaseClientDetails.class);
     }
 
     public BaseClientDetails updateClient(MockMvc mockMvc, String accessToken, BaseClientDetails clientDetails, IdentityZone zone)
@@ -278,15 +276,15 @@ public BaseClientDetails updateClient(MockMvc mockMvc, String accessToken, BaseC
                 .header("Authorization", "Bearer " + accessToken)
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(clientDetails));
+                .content(JsonUtils.writeValueAsString(clientDetails));
         if (! zone.equals(IdentityZone.getUaa())) {
             updateClientPut = updateClientPut.header(IdentityZoneSwitchingFilter.HEADER, zone.getId());
         }
 
-        return new ObjectMapper().readValue(
+        return JsonUtils.readValue(
             mockMvc.perform(updateClientPut)
                 .andExpect(status().isOk())
-                .andReturn().getResponse().getContentAsByteArray(), BaseClientDetails.class);
+                .andReturn().getResponse().getContentAsString(), BaseClientDetails.class);
     }
 
     public String getZoneAdminToken(MockMvc mockMvc, String adminToken, String zoneId) throws Exception {
@@ -315,8 +313,8 @@ public String getUserOAuthAccessToken(MockMvc mockMvc, String clientId, String c
                 .param("password", password)
                 .param("scope", scope);
         MvcResult result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        TestClient.OAuthToken oauthToken = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(),
-                TestClient.OAuthToken.class);
+        TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(),
+            TestClient.OAuthToken.class);
         return oauthToken.accessToken;
     }
 
@@ -330,7 +328,7 @@ public String getClientOAuthAccessToken(MockMvc mockMvc, String clientId, String
             .param("client_id", clientId)
             .param("scope", scope);
         MvcResult result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        TestClient.OAuthToken oauthToken = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(), TestClient.OAuthToken.class);
+        TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), TestClient.OAuthToken.class);
         return oauthToken.accessToken;
     }
 
@@ -376,8 +374,8 @@ public String getUserOAuthAccessTokenAuthCode(MockMvc mockMvc, String clientId,
                 .param(OAuth2Utils.CLIENT_ID, clientId)
                 .param(OAuth2Utils.REDIRECT_URI, "http://localhost/test");
         result = mockMvc.perform(authRequest).andDo(print()).andExpect(status().is2xxSuccessful()).andReturn();
-        TestClient.OAuthToken oauthToken = new ObjectMapper().readValue(result.getResponse().getContentAsByteArray(),
-                TestClient.OAuthToken.class);
+        TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(),
+            TestClient.OAuthToken.class);
         return oauthToken.accessToken;
 
     }
@@ -397,7 +395,7 @@ public String getClientCredentialsOAuthAccessToken(MockMvc mockMvc, String usern
         MvcResult result = mockMvc.perform(oauthTokenPost)
                 .andExpect(status().isOk())
                 .andReturn();
-        OAuthToken oauthToken = objectMapper.readValue(result.getResponse().getContentAsByteArray(), OAuthToken.class);
+        OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), OAuthToken.class);
         return oauthToken.accessToken;
     }
 
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityProviderEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityProviderEndpointsMockMvcTests.java
index e89559c904d..5e816f98ce1 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityProviderEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityProviderEndpointsMockMvcTests.java
@@ -12,6 +12,7 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.mock.zones;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.googlecode.flyway.core.Flyway;
 import org.apache.commons.lang.RandomStringUtils;
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
@@ -32,7 +33,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter;
 import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
 import org.cloudfoundry.identity.uaa.zone.event.IdentityProviderModifiedEvent;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneEndpointsMockMvcTests.java
index 415dd7bb253..223d29de5b6 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneEndpointsMockMvcTests.java
@@ -1,5 +1,7 @@
 package org.cloudfoundry.identity.uaa.mock.zones;
 
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.googlecode.flyway.core.Flyway;
 
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
@@ -25,9 +27,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
 import org.cloudfoundry.identity.uaa.zone.event.IdentityZoneModifiedEvent;
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -75,7 +74,7 @@ public class IdentityZoneEndpointsMockMvcTests extends TestClassNullifier {
     private static TestApplicationEventListener<ClientDeleteEvent> clientDeleteEventListener;
     private static TestApplicationEventListener<GroupModifiedEvent> groupModifiedEventListener;
     private static TestApplicationEventListener<UserModifiedEvent> userModifiedEventListener;
-    
+
     @BeforeClass
     public static void setUp() throws Exception {
         webApplicationContext = new XmlWebApplicationContext();
@@ -94,7 +93,7 @@ public static void setUp() throws Exception {
         clientDeleteEventListener = mockMvcUtils.addEventListener(webApplicationContext, ClientDeleteEvent.class);
         groupModifiedEventListener = mockMvcUtils.addEventListener(webApplicationContext, GroupModifiedEvent.class);
         userModifiedEventListener = mockMvcUtils.addEventListener(webApplicationContext, UserModifiedEvent.class);
-        
+
 
         identityClientToken = testClient.getClientCredentialsOAuthAccessToken(
             "identity",
@@ -131,7 +130,7 @@ public void after() {
     private ScimUser createUser(String token, String subdomain) throws Exception {
         ScimUser user = getScimUser();
 
-        byte[] requestBody = new ObjectMapper().writeValueAsBytes(user);
+        byte[] requestBody = JsonUtils.writeValueAsBytes(user);
         MockHttpServletRequestBuilder post = post("/Users")
                 .header("Authorization", "Bearer " + token)
                 .contentType(APPLICATION_JSON)
@@ -147,7 +146,7 @@ private ScimUser createUser(String token, String subdomain) throws Exception {
                 .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
                 .andReturn();
 
-        return new ObjectMapper().readValue(result.getResponse().getContentAsString(), ScimUser.class);
+        return JsonUtils.readValue(result.getResponse().getContentAsString(), ScimUser.class);
     }
 
     private ScimUser getScimUser() {
@@ -169,7 +168,7 @@ public void testGetZoneAsIdentityClient() throws Exception  {
         assertEquals(created.getSubdomain(), retrieved.getSubdomain());
         assertEquals(created.getDescription(), retrieved.getDescription());
     }
-    
+
     @Test
     public void testGetZonesAsIdentityClient() throws Exception  {
         String id = generator.generate();
@@ -178,8 +177,8 @@ public void testGetZonesAsIdentityClient() throws Exception  {
                 .header("Authorization", "Bearer " + identityClientToken))
                 .andExpect(status().isOk())
                 .andReturn();
-        
-        
+
+
         List<IdentityZone> zones = JsonUtils.readValue(result.getResponse().getContentAsString(), new TypeReference<List<IdentityZone>>() {});
         IdentityZone retrieved = null;
         for (IdentityZone identityZone : zones) {
@@ -187,7 +186,7 @@ public void testGetZonesAsIdentityClient() throws Exception  {
                 retrieved = identityZone;
             }
         }
-        
+
         assertEquals(created.getId(), retrieved.getId());
         assertEquals(created.getName(), retrieved.getName());
         assertEquals(created.getSubdomain(), retrieved.getSubdomain());
@@ -264,9 +263,9 @@ public void testUpdateWithSameDataReturns200() throws Exception {
         String id = generator.generate();
 
         IdentityZone created = createZone(id, HttpStatus.CREATED, identityClientToken);
-        
+
         checkZoneAuditEventInUaa(1, AuditEventType.IdentityZoneCreatedEvent);
-        
+
         updateZone(created, HttpStatus.OK, identityClientToken);
         checkZoneAuditEventInUaa(2, AuditEventType.IdentityZoneModifiedEvent);
     }
@@ -320,7 +319,7 @@ public void testUpdateZoneInsufficientScope() throws Exception {
     public void testCreateDuplicateZoneReturns409() throws Exception {
         String id = generator.generate();
         createZone(id, HttpStatus.CREATED, identityClientToken);
-        
+
         checkZoneAuditEventInUaa(1, AuditEventType.IdentityZoneCreatedEvent);
 
         createZone(id, HttpStatus.CONFLICT, identityClientToken);
@@ -336,7 +335,7 @@ public void testCreateZoneAndIdentityProvider() throws Exception {
         mockMvc.perform(post("/identity-zones")
             .header("Authorization", "Bearer "+identityClientToken)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone)))
+            .content(JsonUtils.writeValueAsString(identityZone)))
             .andExpect(status().isCreated())
             .andReturn();
 
@@ -347,7 +346,7 @@ public void testCreateZoneAndIdentityProvider() throws Exception {
         IdentityProvider idp2 = idpp.retrieveByOrigin(Origin.UAA, IdentityZone.getUaa().getId());
         assertNotEquals(idp1,  idp2);
     }
-    
+
     @Test
     public void testCreateAndDeleteLimitedClientInNewZoneUsingZoneEndpoint() throws Exception {
         String id = generator.generate();
@@ -361,20 +360,20 @@ public void testCreateAndDeleteLimitedClientInNewZoneUsingZoneEndpoint() throws
                 .header("Authorization", "Bearer " + identityClientToken)
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(client)))
+                .content(JsonUtils.writeValueAsString(client)))
                 .andExpect(status().isCreated()).andReturn();
-        BaseClientDetails created = new ObjectMapper().readValue(result.getResponse().getContentAsString(), BaseClientDetails.class);
+        BaseClientDetails created = JsonUtils.readValue(result.getResponse().getContentAsString(), BaseClientDetails.class);
         assertNull(created.getClientSecret());
         assertEquals("zones.write", created.getAdditionalInformation().get(ClientConstants.CREATED_WITH));
         assertEquals(Collections.singletonList(Origin.UAA), created.getAdditionalInformation().get(ClientConstants.ALLOWED_PROVIDERS));
         assertEquals("bar", created.getAdditionalInformation().get("foo"));
         checkAuditEventListener(1, AuditEventType.ClientCreateSuccess, clientCreateEventListener, id, "http://localhost:8080/uaa/oauth/token", "identity");
-        
+
         mockMvc.perform(delete("/identity-zones/"+zone.getId()+"/clients/"+created.getClientId(), IdentityZone.getUaa().getId())
                 .header("Authorization", "Bearer " + identityClientToken)
                 .accept(APPLICATION_JSON))
                 .andExpect(status().isOk());
-        
+
         checkAuditEventListener(1, AuditEventType.ClientDeleteSuccess, clientDeleteEventListener, id, "http://localhost:8080/uaa/oauth/token", "identity");
     }
 
@@ -388,18 +387,18 @@ public void testCreateAndDeleteLimitedClientInUAAZoneReturns403() throws Excepti
                 .header("Authorization", "Bearer " + identityClientToken)
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(client)))
+                .content(JsonUtils.writeValueAsString(client)))
                 .andExpect(status().isForbidden());
         assertEquals(0, clientCreateEventListener.getEventCount());
-        
+
         mockMvc.perform(delete("/identity-zones/uaa/clients/admin")
                 .header("Authorization", "Bearer " + identityClientToken)
                 .accept(APPLICATION_JSON))
                 .andExpect(status().isForbidden());
-        
+
         assertEquals(0, clientDeleteEventListener.getEventCount());
     }
-    
+
     @Test
     public void testCreateAdminClientInNewZoneUsingZoneEndpointReturns400() throws Exception {
         String id = generator.generate();
@@ -411,7 +410,7 @@ public void testCreateAdminClientInNewZoneUsingZoneEndpointReturns400() throws E
                 .header("Authorization", "Bearer " + identityClientToken)
                 .contentType(APPLICATION_JSON)
                 .accept(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(client)))
+                .content(JsonUtils.writeValueAsString(client)))
                 .andExpect(status().isBadRequest());
     }
 
@@ -430,7 +429,7 @@ public void testCreateInvalidZone() throws Exception {
         mockMvc.perform(post("/identity-zones")
             .header("Authorization", "Bearer "+identityClientToken)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone)))
+            .content(JsonUtils.writeValueAsString(identityZone)))
             .andExpect(status().isBadRequest());
 
         assertEquals(0, zoneModifiedEventListener.getEventCount());
@@ -449,7 +448,7 @@ public void testCreatesZonesWithDuplicateSubdomains() throws Exception {
             .header("Authorization", "Bearer "+identityClientToken)
             .contentType(APPLICATION_JSON)
             .accept(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone1)))
+            .content(JsonUtils.writeValueAsString(identityZone1)))
             .andExpect(status().isCreated());
 
         checkZoneAuditEventInUaa(1, AuditEventType.IdentityZoneCreatedEvent);
@@ -458,7 +457,7 @@ public void testCreatesZonesWithDuplicateSubdomains() throws Exception {
             .header("Authorization", "Bearer "+identityClientToken)
             .contentType(APPLICATION_JSON)
             .accept(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone2)))
+            .content(JsonUtils.writeValueAsString(identityZone2)))
             .andExpect(status().isConflict());
 
         assertEquals(1, zoneModifiedEventListener.getEventCount());
@@ -471,7 +470,7 @@ public void testSuccessfulUserManagementInZoneUsingAdminClient() throws Exceptio
         adminClient.setClientSecret("admin-secret");
         IdentityZoneCreationResult creationResult = mockMvcUtils.createOtherIdentityZoneAndReturnResult(subdomain, mockMvc, webApplicationContext, adminClient);
         IdentityZone identityZone = creationResult.getIdentityZone();
-        
+
         checkZoneAuditEventInUaa(1, AuditEventType.IdentityZoneCreatedEvent);
         checkAuditEventListener(1, AuditEventType.GroupCreatedEvent, groupModifiedEventListener, IdentityZone.getUaa().getId(), "http://localhost:8080/uaa/oauth/token", "identity");
         checkAuditEventListener(1, AuditEventType.ClientCreateSuccess, clientCreateEventListener, identityZone.getId(), "http://localhost:8080/uaa/oauth/token", creationResult.getZoneAdminUser().getId());
@@ -479,22 +478,22 @@ public void testSuccessfulUserManagementInZoneUsingAdminClient() throws Exceptio
         String zoneAdminToken = testClient.getClientCredentialsOAuthAccessToken("admin", "admin-secret", "scim.write,scim.read", subdomain);
         ScimUser user = createUser(zoneAdminToken, subdomain);
         checkAuditEventListener(1, AuditEventType.UserCreatedEvent, userModifiedEventListener, identityZone.getId(), "http://"+subdomain+".localhost:8080/uaa/oauth/token", "admin");
-       
+
         user.setUserName("updated-username@test.com");
         MockHttpServletRequestBuilder put = put("/Users/" + user.getId())
             .header("Authorization", "Bearer " + zoneAdminToken)
             .header("If-Match", "\"" + user.getVersion() + "\"")
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(user))
+            .content(JsonUtils.writeValueAsString(user))
             .with(new SetServerNameRequestPostProcessor(subdomain + ".localhost"));
 
         MvcResult result = mockMvc.perform(put)
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.userName").value(user.getUserName()))
             .andReturn();
-        
+
         checkAuditEventListener(2, AuditEventType.UserModifiedEvent, userModifiedEventListener, identityZone.getId(), "http://"+subdomain+".localhost:8080/uaa/oauth/token", "admin");
-        user = new ObjectMapper().readValue(result.getResponse().getContentAsString(), ScimUser.class);
+        user = JsonUtils.readValue(result.getResponse().getContentAsString(), ScimUser.class);
         List<ScimUser> users = getUsersInZone(subdomain, zoneAdminToken);
         assertTrue(users.contains(user));
         assertEquals(1, users.size());
@@ -521,8 +520,9 @@ private List<ScimUser> getUsersInZone(String subdomain, String token) throws Exc
 
         MvcResult mvcResult = mockMvc.perform(get).andExpect(status().isOk()).andReturn();
 
-        JsonNode root = new ObjectMapper().readTree(mvcResult.getResponse().getContentAsString());
-        return new ObjectMapper().readValue(root.get("resources").toString(), new TypeReference<List<ScimUser>>() {});
+        JsonNode root = JsonUtils.readTree(mvcResult.getResponse().getContentAsString());
+        return JsonUtils.readValue(root.get("resources").toString(), new TypeReference<List<ScimUser>>() {
+        });
     }
 
     @Test
@@ -536,7 +536,7 @@ public void testCreateAndListUsersInOtherZoneIsUnauthorized() throws Exception {
 
         ScimUser user = getScimUser();
 
-        byte[] requestBody = new ObjectMapper().writeValueAsBytes(user);
+        byte[] requestBody = JsonUtils.writeValueAsBytes(user);
         MockHttpServletRequestBuilder post = post("/Users")
             .with(new SetServerNameRequestPostProcessor(subdomain + ".localhost"))
             .header("Authorization", "Bearer " + defaultZoneAdminToken)
@@ -568,7 +568,7 @@ public void testModifyandDeleteUserInOtherZoneIsUnauthorized() throws Exception
             .header("Authorization", "Bearer " + zoneAdminToken)
             .header("If-Match", "\"" + user.getVersion() + "\"")
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(user));
+            .content(JsonUtils.writeValueAsString(user));
 
         mockMvc.perform(put)
             .andExpect(status().isUnauthorized())
@@ -601,7 +601,7 @@ private IdentityZone createZone(String id, HttpStatus expect, String token) thro
         MvcResult result = mockMvc.perform(post("/identity-zones")
             .header("Authorization", "Bearer " + token)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone)))
+            .content(JsonUtils.writeValueAsString(identityZone)))
             .andExpect(status().is(expect.value()))
             .andReturn();
 
@@ -615,7 +615,7 @@ private IdentityZone updateZone(IdentityZone identityZone, HttpStatus expect, St
         MvcResult result = mockMvc.perform(put("/identity-zones/" + identityZone.getId())
             .header("Authorization", "Bearer " + token)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(identityZone)))
+            .content(JsonUtils.writeValueAsString(identityZone)))
             .andExpect(status().is(expect.value()))
             .andReturn();
 
@@ -624,11 +624,11 @@ private IdentityZone updateZone(IdentityZone identityZone, HttpStatus expect, St
         }
         return null;
     }
-    
+
     private <T extends AbstractUaaEvent> void checkZoneAuditEventInUaa(int eventCount, AuditEventType eventType) {
         checkAuditEventListener(eventCount, eventType, zoneModifiedEventListener, IdentityZone.getUaa().getId(), "http://localhost:8080/uaa/oauth/token", "identity");
     }
-    
+
     private <T extends AbstractUaaEvent> void checkAuditEventListener(int eventCount, AuditEventType eventType, TestApplicationEventListener<T> eventListener, String identityZoneId, String issuer, String subject) {
         T event = eventListener.getLatestEvent();
         assertEquals(eventCount, eventListener.getEventCount());
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneSwitchingFilterMockMvcTest.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneSwitchingFilterMockMvcTest.java
index c87375f3fbb..c3f1a0a4e98 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneSwitchingFilterMockMvcTest.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/zones/IdentityZoneSwitchingFilterMockMvcTest.java
@@ -21,10 +21,10 @@
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.SetServerNameRequestPostProcessor;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -96,7 +96,7 @@ public void testSwitchingZones() throws Exception {
                 .header("Authorization", "Bearer " + zoneAdminToken)
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsString(client)))
+                .content(JsonUtils.writeValueAsString(client)))
             .andExpect(status().isCreated());
 
         // Authenticate with new Client in new Zone
@@ -156,7 +156,7 @@ private void createClientInOtherZone(String accessToken, String zoneId, ResultMa
             .header("Authorization", "Bearer " + accessToken)
             .accept(APPLICATION_JSON)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsString(client)))
+            .content(JsonUtils.writeValueAsString(client)))
             .andExpect(statusMatcher);
     }
 }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsMockMvcTests.java
index 762b7d1f5f6..5c9271f6805 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/PasswordResetEndpointsMockMvcTests.java
@@ -12,13 +12,13 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.scim.endpoints;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.googlecode.flyway.core.Flyway;
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -83,7 +83,7 @@ public void testAPasswordReset() throws Exception {
                 .andReturn();
 
         String responseString = result.getResponse().getContentAsString();
-        Map<String,String> response = new ObjectMapper().readValue(responseString, new TypeReference<Map<String, String>>() {
+        Map<String,String> response = JsonUtils.readValue(responseString, new TypeReference<Map<String, String>>() {
         });
 
         post = post("/password_change")
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
index 9b7683533db..5bf4373a8ae 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
@@ -29,8 +29,8 @@
 import org.cloudfoundry.identity.uaa.scim.jdbc.JdbcScimGroupProvisioning;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -149,7 +149,7 @@ public void testIdentityClientManagesZoneAdmins() throws Exception {
             .accept(APPLICATION_JSON)
             .contentType(APPLICATION_JSON)
             .header("Authorization", "Bearer " + identityClientToken)
-            .content(new ObjectMapper().writeValueAsBytes(group));
+            .content(JsonUtils.writeValueAsBytes(group));
         //create the zones.{id}.admin
         mockMvc.perform(post)
             .andDo(print())
@@ -170,7 +170,7 @@ public void testIdentityClientManagesZoneAdmins() throws Exception {
             .accept(APPLICATION_JSON)
             .contentType(APPLICATION_JSON)
             .header("Authorization", "Bearer " + scimWriteToken)
-            .content(new ObjectMapper().writeValueAsBytes(group)))
+            .content(JsonUtils.writeValueAsBytes(group)))
             .andExpect(status().isForbidden());
 
         mockMvc.perform(
@@ -201,7 +201,7 @@ public void testIdentityClientManagesZoneAdmins() throws Exception {
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
                 .header("Authorization", "Bearer " + identityClientToken)
-                .content(new ObjectMapper().writeValueAsBytes(group));
+                .content(JsonUtils.writeValueAsBytes(group));
             //create the zones.{id}.admin
             mockMvc.perform(post)
                 .andExpect(status().isCreated());
@@ -381,7 +381,7 @@ protected ResultActions createGroup(String id, String name, String externalName)
         if (id!=null) em.setGroupId(id);
         if (externalName!=null) em.setExternalGroup(externalName);
         if (name!=null) em.setDisplayName(name);
-        String content = new ObjectMapper().writeValueAsString(em);
+        String content = JsonUtils.writeValueAsString(em);
         MockHttpServletRequestBuilder post = MockMvcRequestBuilders.post("/Groups/External")
             .header("Authorization", "Bearer " + scimWriteToken)
             .contentType(MediaType.APPLICATION_JSON)
@@ -548,7 +548,7 @@ protected void checkGetExternalGroupsFilter(String fieldName, String fieldValue)
         String content = result.andReturn().getResponse().getContentAsString();
         SearchResults<ScimGroupExternalMember> members = null;
 
-        Map<String,Object> map = new ObjectMapper().readValue(content, Map.class);
+        Map<String,Object> map = JsonUtils.readValue(content, Map.class);
         List<Map<String,String>> resources = (List<Map<String,String>>)map.get("resources");
         int startIndex = Integer.parseInt(map.get("startIndex").toString());
         int itemsPerPage = Integer.parseInt(map.get("itemsPerPage").toString());
@@ -621,7 +621,7 @@ protected void checkGetExternalGroupsPagination(int start, int count) throws Exc
         String content = result.andReturn().getResponse().getContentAsString();
         SearchResults<ScimGroupExternalMember> members = null;
 
-        Map<String,Object> map = new ObjectMapper().readValue(content, Map.class);
+        Map<String,Object> map = JsonUtils.readValue(content, Map.class);
         List<Map<String,String>> resources = (List<Map<String,String>>)map.get("resources");
         int startIndex = Integer.parseInt(map.get("startIndex").toString());
         int itemsPerPage = Integer.parseInt(map.get("itemsPerPage").toString());
@@ -668,7 +668,7 @@ protected void checkGetExternalGroups(String path) throws Exception {
         String content = result.andReturn().getResponse().getContentAsString();
         SearchResults<ScimGroupExternalMember> members = null;
 
-        Map<String,Object> map = new ObjectMapper().readValue(content, Map.class);
+        Map<String,Object> map = JsonUtils.readValue(content, Map.class);
         List<Map<String,String>> resources = (List<Map<String,String>>)map.get("resources");
         int startIndex = Integer.parseInt(map.get("startIndex").toString());
         int itemsPerPage = Integer.parseInt(map.get("itemsPerPage").toString());
@@ -737,7 +737,7 @@ private void createScimClient(String adminAccessToken, String id, String secret)
                 .header("Authorization", "Bearer " + adminAccessToken)
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsBytes(client));
+                .content(JsonUtils.writeValueAsBytes(client));
         mockMvc.perform(createClientPost).andExpect(status().isCreated());
     }
 
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserEndpointsMockMvcTests.java
index 5c40ca7b830..8585a35bc00 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserEndpointsMockMvcTests.java
@@ -19,16 +19,13 @@
 import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.SetServerNameRequestPostProcessor;
-import org.cloudfoundry.identity.uaa.zone.IdentityZone;
-import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
-import org.springframework.security.oauth2.provider.client.BaseClientDetails;
 import org.springframework.security.web.FilterChainProxy;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
@@ -37,9 +34,6 @@
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 import org.springframework.web.context.support.XmlWebApplicationContext;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import static org.springframework.http.MediaType.APPLICATION_JSON;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -93,7 +87,7 @@ private ScimUser createUser(String token, String subdomain) throws Exception {
     }
 
     private ScimUser createUser(ScimUser user, String token, String subdomain) throws Exception {
-        byte[] requestBody = new ObjectMapper().writeValueAsBytes(user);
+        byte[] requestBody = JsonUtils.writeValueAsBytes(user);
         MockHttpServletRequestBuilder post = post("/Users")
             .header("Authorization", "Bearer " + token)
             .contentType(APPLICATION_JSON)
@@ -109,7 +103,7 @@ private ScimUser createUser(ScimUser user, String token, String subdomain) throw
                 .andExpect(jsonPath("$.name.givenName").value(user.getGivenName()))
             .andReturn();
 
-        return new ObjectMapper().readValue(result.getResponse().getContentAsString(), ScimUser.class);
+        return JsonUtils.readValue(result.getResponse().getContentAsString(), ScimUser.class);
     }
 
     private ScimUser getScimUser() {
@@ -172,7 +166,7 @@ public void testCreateUserInOtherZoneIsUnauthorized() throws Exception {
 
         ScimUser user = getScimUser();
 
-        byte[] requestBody = new ObjectMapper().writeValueAsBytes(user);
+        byte[] requestBody = JsonUtils.writeValueAsBytes(user);
         MockHttpServletRequestBuilder post = post("/Users")
                 .with(new SetServerNameRequestPostProcessor(otherSubdomain + ".localhost"))
                 .header("Authorization", "Bearer " + zoneAdminToken)
@@ -255,7 +249,7 @@ private void updateUser(String token, int status) throws Exception {
             .header("If-Match", "\"" + user.getVersion() + "\"")
             .accept(APPLICATION_JSON)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsBytes(user));
+            .content(JsonUtils.writeValueAsBytes(user));
 
         if (status==HttpStatus.OK.value()) {
             mockMvc.perform(put)
@@ -289,7 +283,7 @@ private void createScimClient(String adminAccessToken, String id, String secret)
                 .header("Authorization", "Bearer " + adminAccessToken)
                 .accept(APPLICATION_JSON)
                 .contentType(APPLICATION_JSON)
-                .content(new ObjectMapper().writeValueAsBytes(client));
+                .content(JsonUtils.writeValueAsBytes(client));
         mockMvc.perform(createClientPost).andExpect(status().isCreated());
     }
 }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
index 3e0f4f50257..d483b4a9f1f 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
@@ -20,7 +20,7 @@
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
 import org.cloudfoundry.identity.uaa.test.YamlServletProfileInitializerContextInitializer;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -222,7 +222,7 @@ private static void createScimClient(String adminAccessToken, String id, String
             .header("Authorization", "Bearer " + adminAccessToken)
             .accept(APPLICATION_JSON)
             .contentType(APPLICATION_JSON)
-            .content(new ObjectMapper().writeValueAsBytes(client));
+            .content(JsonUtils.writeValueAsBytes(client));
         mockMvc.perform(createClientPost).andExpect(status().isCreated());
     }
 
@@ -253,7 +253,7 @@ private MockHttpServletRequestBuilder getUsernameLookupRequest(String token, Str
     }
 
     private void validateLookupResults(String[] usernames, String body) throws java.io.IOException {
-        Map<String, Object> map = new ObjectMapper().readValue(body, Map.class);
+        Map<String, Object> map = JsonUtils.readValue(body, Map.class);
         assertTrue("Response should contain 'resources' object", map.get("resources")!=null);
         assertTrue("Response should contain 'startIndex' object", map.get("startIndex")!=null);
         assertTrue("Response should contain 'itemsPerPage' object", map.get("itemsPerPage")!=null);
@@ -298,7 +298,7 @@ private static String[][] createUsers(String token, int count) throws Exception
             user.setName(new ScimUser.Name("Joe", "User"));
             user.addEmail(email);
 
-            byte[] requestBody = new ObjectMapper().writeValueAsBytes(user);
+            byte[] requestBody = JsonUtils.writeValueAsBytes(user);
             MockHttpServletRequestBuilder post = post("/Users")
                 .header("Authorization", "Bearer " + token)
                 .contentType(APPLICATION_JSON)
@@ -312,7 +312,7 @@ private static String[][] createUsers(String token, int count) throws Exception
                 .andExpect(jsonPath("$.name.familyName").value("User"))
                 .andExpect(jsonPath("$.name.givenName").value("Joe"))
                 .andReturn().getResponse().getContentAsString();
-            Map<String,Object> map = new ObjectMapper().readValue(body, Map.class);
+            Map<String,Object> map = JsonUtils.readValue(body, Map.class);
             result[i] = new String[] {map.get("id").toString(), email};
         }
         return result;
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
index 714488df6f4..a3615675591 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
@@ -12,28 +12,25 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.test;
 
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.commons.codec.binary.Base64;
+import org.cloudfoundry.identity.uaa.util.JsonUtils;
 import org.cloudfoundry.identity.uaa.util.SetServerNameRequestPostProcessor;
-import org.codehaus.jackson.annotate.JsonIgnoreProperties;
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.codehaus.jackson.map.ObjectMapper;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
 
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
 public class TestClient {
 
     //TODO nullify fields?
     private MockMvc mockMvc;
-    private final ObjectMapper objectMapper;
 
     public TestClient(MockMvc mockMvc) {
         this.mockMvc = mockMvc;
-        objectMapper = new ObjectMapper();
     }
 
     public String getClientCredentialsOAuthAccessToken(String username, String password, String scope) throws Exception {
@@ -53,7 +50,7 @@ public String getClientCredentialsOAuthAccessToken(String username, String passw
         MvcResult result = mockMvc.perform(oauthTokenPost)
             .andExpect(status().isOk())
             .andReturn();
-        OAuthToken oauthToken = objectMapper.readValue(result.getResponse().getContentAsByteArray(), OAuthToken.class);
+        OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), OAuthToken.class);
         return oauthToken.accessToken;
     }
 
@@ -69,7 +66,7 @@ public String getUserOAuthAccessToken(String clientId, String clientSecret, Stri
                         .param("password", password)
                         .param("scope", scope);
         MvcResult result = mockMvc.perform(oauthTokenPost).andExpect(status().isOk()).andReturn();
-        OAuthToken oauthToken = objectMapper.readValue(result.getResponse().getContentAsByteArray(), OAuthToken.class);
+        OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), OAuthToken.class);
         return oauthToken.accessToken;
     }
 

From b7908503dc654693f61eaeb80bd949895a02c51f Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Tue, 5 May 2015 17:47:03 -0600
Subject: [PATCH 3/9] Attempt to upgrade to Spring Security 4
 http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html#m3to4-xmlnamespace-http
 Check for hasAuthority when we are dealing with clients only, hasRole no
 longer checks authorities Upgrade Spring Security SAML to 1.0.1
 https://www.pivotaltracker.com/story/show/93706906 [#93706906]

---
 common/build.gradle                           |  2 +-
 .../uaa/ldap/ExtendedLdapUserMapper.java      | 19 ++++++++-
 .../ldap/PasswordComparisonAuthenticator.java |  2 +-
 .../extension/SpringSecurityLdapTemplate.java |  2 +-
 .../uaa/login/XFrameOptionsFilter.java        |  2 +-
 .../web/DelegatingRequestMatcher.java         |  8 ++--
 .../uaa/security/web/UaaRequestMatcher.java   | 10 ++---
 login/src/main/resources/login-ui.xml         | 29 +++++++++-----
 .../main/webapp/WEB-INF/spring-servlet.xml    | 12 +++---
 .../main/webapp/WEB-INF/spring-servlet.xml    | 16 ++++----
 shared_versions.gradle                        |  5 ++-
 uaa/src/main/resources/ldap-integration.xml   |  2 +-
 .../main/webapp/WEB-INF/spring-servlet.xml    | 40 +++++++++----------
 .../WEB-INF/spring/approvals-endpoints.xml    |  9 +++--
 .../WEB-INF/spring/client-admin-endpoints.xml | 13 +++---
 .../WEB-INF/spring/codestore-endpoints.xml    | 28 ++++++++-----
 .../WEB-INF/spring/login-server-security.xml  | 34 +++++++++-------
 .../WEB-INF/spring/multitenant-endpoints.xml  |  4 +-
 .../webapp/WEB-INF/spring/oauth-endpoints.xml | 20 ++++++----
 .../WEB-INF/spring/openid-endpoints.xml       |  7 ++--
 .../WEB-INF/spring/resource-endpoints.xml     |  9 +++--
 .../webapp/WEB-INF/spring/saml-providers.xml  | 15 +++----
 .../webapp/WEB-INF/spring/scim-endpoints.xml  | 34 +++++++++-------
 .../NativeApplicationIntegrationTests.java    | 11 +++--
 .../RefreshTokenSupportIntegrationTests.java  |  4 +-
 .../token/TokenKeyEndpointMockMvcTests.java   | 21 +++++++++-
 uaa/src/test/resources/test-security.xml      |  2 +-
 27 files changed, 222 insertions(+), 138 deletions(-)

diff --git a/common/build.gradle b/common/build.gradle
index 2efeee69c54..de82dbb63f0 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -50,7 +50,7 @@ dependencies {
   compile group: 'com.googlecode.flyway', name: 'flyway-core', version:'2.3.1'
   compile group: 'org.hsqldb', name: 'hsqldb', version:'2.3.1'
 
-  compile(group: 'org.springframework.security.extensions', name: 'spring-security-saml2-core', version:'1.0.0.RELEASE') {
+  compile(group: 'org.springframework.security.extensions', name: 'spring-security-saml2-core', version:parent.springSecuritySamlVersion) {
     exclude(module: 'bcprov-jdk15')
   }
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/ExtendedLdapUserMapper.java b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/ExtendedLdapUserMapper.java
index 425e9beed80..aefd8c0a959 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/ExtendedLdapUserMapper.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/ExtendedLdapUserMapper.java
@@ -23,9 +23,14 @@
 import org.springframework.security.ldap.userdetails.LdapUserDetails;
 import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
 
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -47,7 +52,19 @@ public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
         List<String> attributeNames = Collections.list(adapter.getAttributes().getIDs());
         for (String attributeName : attributeNames) {
             try {
-                String[] values = adapter.getStringAttributes(attributeName);
+                Object[] objValues = adapter.getObjectAttributes(attributeName);
+                String[] values = new String[objValues!=null ? objValues.length : 0];
+                for (int i=0; i<values.length; i++) {
+                    if (objValues[i] != null) {
+                        if (objValues[i].getClass().isAssignableFrom(String.class)) {
+                            values[i] = (String)objValues[i];
+                        } else if  (objValues[i] instanceof byte[]) {
+                            values[i] = new String((byte[])objValues[i]);
+                        } else {
+                            values[i] = objValues[i].toString();
+                        }
+                    }
+                }
                 if (values == null || values.length == 0) {
                     logger.debug("No attribute value found for '" + attributeName + "'");
                 } else {
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/PasswordComparisonAuthenticator.java b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/PasswordComparisonAuthenticator.java
index 8e9ae68a7e5..58caad3d66c 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/PasswordComparisonAuthenticator.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/PasswordComparisonAuthenticator.java
@@ -75,7 +75,7 @@ public DirContextOperations authenticate(Authentication authentication) {
         }
 
         if (user == null) {
-            throw new UsernameNotFoundException("User not found: " + username, username);
+            throw new UsernameNotFoundException("User not found: " + username);
         }
 
         if (logger.isDebugEnabled()) {
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/extension/SpringSecurityLdapTemplate.java b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/extension/SpringSecurityLdapTemplate.java
index 0cfa4923b42..ab16ef724af 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/extension/SpringSecurityLdapTemplate.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/ldap/extension/SpringSecurityLdapTemplate.java
@@ -24,8 +24,8 @@
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DirContextOperations;
 import org.springframework.ldap.core.DistinguishedName;
-import org.springframework.ldap.core.LdapEncoder;
 import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.support.LdapEncoder;
 import org.springframework.security.ldap.LdapUtils;
 import org.springframework.util.Assert;
 
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/login/XFrameOptionsFilter.java b/common/src/main/java/org/cloudfoundry/identity/uaa/login/XFrameOptionsFilter.java
index e5ca82d61af..93c70aeb47a 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/login/XFrameOptionsFilter.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/login/XFrameOptionsFilter.java
@@ -12,7 +12,7 @@ public class XFrameOptionsFilter extends OncePerRequestFilter {
 
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
-        response.addHeader("X-Frame-Options", "DENY");
+        response.setHeader("X-Frame-Options", "DENY");
         filterChain.doFilter(request, response);
     }
 }
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/DelegatingRequestMatcher.java b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/DelegatingRequestMatcher.java
index a7eead4eeac..f1dd6e893c4 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/DelegatingRequestMatcher.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/DelegatingRequestMatcher.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -13,13 +13,13 @@
 
 package org.cloudfoundry.identity.uaa.security.web;
 
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.springframework.security.web.util.RequestMatcher;
-
 /**
  * @author Luke Taylor
  */
@@ -27,7 +27,7 @@ public class DelegatingRequestMatcher implements RequestMatcher {
     private final List<RequestMatcher> matchers;
 
     public DelegatingRequestMatcher(List<RequestMatcher> matchers) {
-        this.matchers = new ArrayList<RequestMatcher>(matchers);
+        this.matchers = new ArrayList<>(matchers);
     }
 
     @Override
diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcher.java b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcher.java
index bd23a5bdb75..8cb881a02e5 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcher.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcher.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -26,7 +26,7 @@
 import org.springframework.beans.factory.BeanNameAware;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
-import org.springframework.security.web.util.RequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.util.Assert;
 
 /**
@@ -67,7 +67,7 @@ public UaaRequestMatcher(String path) {
     /**
      * The HttpMethod that the request should be made with. Optional (if null,
      * then all values match)
-     * 
+     *
      * @param method
      */
     public void setMethod(HttpMethod method) {
@@ -78,7 +78,7 @@ public void setMethod(HttpMethod method) {
      * A media type that should be present in the accept header for a request to
      * match. Optional (if null then all
      * values match).
-     * 
+     *
      * @param accepts the accept header value to set
      */
     public void setAccept(List<String> accepts) {
@@ -90,7 +90,7 @@ public void setAccept(List<String> accepts) {
      * A map of request parameter name and values to match against. If all the
      * specified parameters are present and
      * match the values given then the accept header will be ignored.
-     * 
+     *
      * @param parameters the parameter matches to set
      */
     public void setParameters(Map<String, String> parameters) {
diff --git a/login/src/main/resources/login-ui.xml b/login/src/main/resources/login-ui.xml
index e3d326deaae..4226b60c2ee 100644
--- a/login/src/main/resources/login-ui.xml
+++ b/login/src/main/resources/login-ui.xml
@@ -22,7 +22,7 @@
   xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
   xmlns:util="http://www.springframework.org/schema/util"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
-    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
@@ -41,31 +41,35 @@
     </bean>
 
     <!-- Pattern: /oauth/authorize parameters:{response_type=code,code=?} -->
-    <http request-matcher-ref="autologinAuthorizeRequestMatcher" entry-point-ref="loginEntryPoint"
+    <http name="secFilterAutologinAuthorize" request-matcher-ref="autologinAuthorizeRequestMatcher" entry-point-ref="loginEntryPoint"
           xmlns="http://www.springframework.org/schema/security">
         <!-- TODO: add entry point that can redirect back to client app? -->
         <anonymous enabled="false" />
         <custom-filter ref="autologinAuthenticationFilter" position="FORM_LOGIN_FILTER" />
+        <csrf disabled="true"/>
     </http>
 
 
   <!-- Pattern:/autologin -->
-    <http name="autologinSecurity" pattern="/autologin" create-session="stateless" entry-point-ref="basicAuthenticationEntryPoint"
-        xmlns="http://www.springframework.org/schema/security" authentication-manager-ref="emptyAuthenticationManager">
+    <http name="secFilterAutologin" pattern="/autologin" create-session="stateless" entry-point-ref="basicAuthenticationEntryPoint"
+        xmlns="http://www.springframework.org/schema/security" authentication-manager-ref="emptyAuthenticationManager" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <anonymous enabled="false" />
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="backwardsCompatibleScopeParameter" class="org.cloudfoundry.identity.uaa.oauth.BackwardsCompatibleScopeParsingFilter"/>
 
-    <http name="uiSecurity" request-matcher-ref="uiRequestMatcher" access-denied-page="/"
+    <http name="uiSecurity" request-matcher-ref="uiRequestMatcher" use-expressions="false"
           authentication-manager-ref="zoneAwareAuthzAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
+      <access-denied-handler error-page="/"/>
       <intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
       <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
       <form-login login-page="/login" username-parameter="username" password-parameter="password"
                            login-processing-url="/login.do" authentication-failure-handler-ref="loginAuthenticationFailureHandler" authentication-details-source-ref="authenticationDetailsSource"/>
       <logout logout-url="/logout.do" success-handler-ref="logoutHandler" />
+      <csrf disabled="true"/>
     </http>
 
 
@@ -81,30 +85,34 @@
     </bean>
 
     <security:http name="resetPasswordSecurity" pattern="/reset_password.do" disable-url-rewriting="true"
-                   entry-point-ref="loginEntryPoint">
+                   entry-point-ref="loginEntryPoint" use-expressions="false">
         <security:intercept-url pattern="/reset_password.do" access="IS_AUTHENTICATED_ANONYMOUSLY" />
         <security:anonymous enabled="true" />
+        <security:csrf disabled="true"/>
     </security:http>
 
     <security:http name="verifyEmailSecurity" pattern="/verify_email" disable-url-rewriting="true"
-                   entry-point-ref="loginEntryPoint">
+                   entry-point-ref="loginEntryPoint" use-expressions="false">
         <security:intercept-url pattern="/verify_email" access="IS_AUTHENTICATED_ANONYMOUSLY" />
         <security:anonymous enabled="true" />
+        <security:csrf disabled="true"/>
     </security:http>
 
     <security:http name="verifyUserSecurity" pattern="/verify_user" disable-url-rewriting="true"
-                   entry-point-ref="loginEntryPoint">
+                   entry-point-ref="loginEntryPoint" use-expressions="false">
         <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
         <security:anonymous enabled="true" />
+        <security:csrf disabled="true"/>
     </security:http>
 
     <security:http name="acceptInvitationSecurity" pattern="/invitations/accept" disable-url-rewriting="true"
-                   entry-point-ref="loginEntryPoint">
+                   entry-point-ref="loginEntryPoint" use-expressions="false">
         <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
         <security:anonymous enabled="true" />
+        <security:csrf disabled="true"/>
     </security:http>
 
-    <security:http name="openIdSecurity">
+    <security:http name="openIdSecurity" use-expressions="false">
         <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <security:custom-filter before="FIRST" ref="metadataGeneratorFilter" />
         <security:custom-filter after="FIRST" ref="httpsHeaderFilter" />
@@ -131,6 +139,7 @@
             </security:attribute-exchange>
         </security:openid-login>
         <security:anonymous enabled="false" />
+        <security:csrf disabled="true"/>
     </security:http>
 
 
diff --git a/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml b/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
index 4e397a54845..1d73aa23d70 100755
--- a/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -10,23 +10,25 @@
        xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
 	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 		http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
 		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
-	<http pattern="/index.html" security="none" xmlns="http://www.springframework.org/schema/security" />
+	<http pattern="/index.html" security="none" xmlns="http://www.springframework.org/schema/security"/>
 	<http pattern="/browse" security="none" xmlns="http://www.springframework.org/schema/security" />
 	<http pattern="/denied" security="none" xmlns="http://www.springframework.org/schema/security" />
 	<http pattern="/js/**" security="none" xmlns="http://www.springframework.org/schema/security" />
 
 	<!-- TODO: make an access denied view that tells me something useful -->
-	<http access-denied-page="/denied" entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
-		xmlns="http://www.springframework.org/schema/security">
+	<http name="apiDefaultFilter" entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
+		xmlns="http://www.springframework.org/schema/security" use-expressions="false">
+		<access-denied-handler error-page="/denied"/>
 		<intercept-url pattern="/info" access="IS_AUTHENTICATED_ANONYMOUSLY" />
 		<intercept-url pattern="/apps" access="scope=cloud_controller.read" />
 		<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
 		<custom-filter ref="oauth2ServiceFilter" position="PRE_AUTH_FILTER" />
 		<custom-filter ref="contentTypeFilter" after="EXCEPTION_TRANSLATION_FILTER" />
 		<anonymous />
+		<csrf disabled="true"/>
 	</http>
 
 	<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
@@ -44,7 +46,7 @@
 
 	<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
 		xmlns="http://www.springframework.org/schema/beans">
-		<property name="loginFormUrl" value="${auth.url}" />
+		<constructor-arg value="${auth.url}" />
 	</bean>
 
 	<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
diff --git a/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml b/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
index 88b41d9cad2..05503183abe 100755
--- a/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -11,23 +11,24 @@
 	   xmlns:sec="http://www.springframework.org/schema/security"
 	xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
 		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
 		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
-	<sec:http pattern="/logout" security="none" />
-	<sec:http pattern="/login_error.jsp" security="none" />
-	<sec:http pattern="/resources/**" security="none" />
-	<sec:http pattern="/favicon.ico" security="none" />
+	<sec:http name="appFilterLogout" pattern="/logout" security="none" />
+	<sec:http name="appFilterLoginError" pattern="/login_error.jsp" security="none" />
+	<sec:http name="appFilterResources" pattern="/resources/**" security="none" />
+	<sec:http name="appFilterFavIcon" pattern="/favicon.ico" security="none" />
 
-	<http pattern="/apps.*" request-matcher="regex" xmlns="http://www.springframework.org/schema/security"
+	<http name="appFilterApps" pattern="/apps.*" request-matcher="regex" xmlns="http://www.springframework.org/schema/security"
 		entry-point-ref="loginEntryPoint" disable-url-rewriting="true" use-expressions="true" authentication-manager-ref="authenticationManager">
 		<intercept-url pattern="/apps.*" access="hasRole('cloud_controller.read')" />
 		<anonymous enabled="false" />
 		<custom-filter ref="oauth2ClientFilter" before="PRE_AUTH_FILTER" />
 		<custom-filter ref="accessTokenFilter" position="PRE_AUTH_FILTER" />
+		<csrf disabled="true"/>
 	</http>
 
-	<http xmlns="http://www.springframework.org/schema/security" entry-point-ref="loginEntryPoint"
+	<http name="appFilterDefault" xmlns="http://www.springframework.org/schema/security" entry-point-ref="loginEntryPoint"
 		disable-url-rewriting="true" use-expressions="true" authentication-manager-ref="authenticationManager"
 		security-context-repository-ref="securityContextRepository">
 		<intercept-url pattern="/**" access="isFullyAuthenticated()" />
@@ -35,6 +36,7 @@
 		<anonymous enabled="false" />
 		<custom-filter ref="oauth2ClientFilter" before="PRE_AUTH_FILTER" />
 		<custom-filter ref="socialClientFilter" position="PRE_AUTH_FILTER" />
+		<csrf disabled="true"/>
 	</http>
 
 	<bean id="securityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
diff --git a/shared_versions.gradle b/shared_versions.gradle
index 52338d51d01..cefb7e8b1d6 100644
--- a/shared_versions.gradle
+++ b/shared_versions.gradle
@@ -1,8 +1,9 @@
 ext {
   springVersion = '4.1.6.RELEASE'
-  springSecurityVersion = '3.2.7.RELEASE'
+  springSecurityVersion = '4.0.1.RELEASE'
   springSecurityOAuthVersion = '2.0.7.RELEASE'
-  springSecurityLdapVersion = '1.3.2.RELEASE'
+  springSecurityLdapVersion = '2.0.3.RELEASE'
+  springSecuritySamlVersion = '1.0.1.RELEASE'
   postgresqlVersion = '9.1-901.jdbc3'
   tomcatVersion = '7.0.54'
   springSecurityJwtVersion = '1.0.3.RELEASE'
diff --git a/uaa/src/main/resources/ldap-integration.xml b/uaa/src/main/resources/ldap-integration.xml
index 06a961fdb04..aacf04e10f5 100644
--- a/uaa/src/main/resources/ldap-integration.xml
+++ b/uaa/src/main/resources/ldap-integration.xml
@@ -18,7 +18,7 @@
        xmlns:sec="http://www.springframework.org/schema/security"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
-              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
               http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
 
 
diff --git a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
index 56f66244ad0..a29e3a554ff 100755
--- a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -19,7 +19,7 @@
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
-        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
@@ -37,20 +37,20 @@
     <import resource="classpath:spring/env.xml" />
     <import resource="spring/audit.xml" />
 
-    <sec:http pattern="/resources/**" security="none" />
-    <sec:http pattern="/favicon.ico" security="none" />
-    <sec:http pattern="/info" security="none" />
-    <sec:http pattern="/password/**" security="none" />
-    <sec:http pattern="/healthz/**" security="none" name="healthz"/>
-    <sec:http pattern="/saml/web/**" security="none" />
-    <sec:http pattern="/vendor/**" security="none" />
+    <sec:http name="secFilterOpen01" pattern="/resources/**" security="none" />
+    <sec:http name="secFilterOpen02" pattern="/favicon.ico" security="none" />
+    <sec:http name="secFilterOpen03" pattern="/info" security="none" />
+    <sec:http name="secFilterOpen04" pattern="/password/**" security="none" />
+    <sec:http name="secFilterOpen05Healthz" pattern="/healthz/**" security="none" />
+    <sec:http name="secFilterOpen06" pattern="/saml/web/**" security="none" />
+    <sec:http name="secFilterOpen07" pattern="/vendor/**" security="none" />
     <!--<sec:http pattern="/login" security="none" />-->
-    <sec:http pattern="/error" security="none" />
-    <sec:http pattern="/forgot_password*" security="none" />
-    <sec:http pattern="/reset_password" security="none" />
-    <sec:http pattern="/email_sent" security="none" />
-    <sec:http pattern="/create_account*" security="none" />
-    <sec:http pattern="/accounts/email_sent" security="none" />
+    <sec:http name="secFilterOpen08" pattern="/error" security="none" />
+    <sec:http name="secFilterOpen09" pattern="/forgot_password*" security="none" />
+    <sec:http name="secFilterOpen10" pattern="/reset_password" security="none" />
+    <sec:http name="secFilterOpen11" pattern="/email_sent" security="none" />
+    <sec:http name="secFilterOpen12" pattern="/create_account*" security="none" />
+    <sec:http name="secFilterOpen13" pattern="/accounts/email_sent" security="none" />
 
     <bean id="xFrameOptionsFilter" class="org.cloudfoundry.identity.uaa.login.XFrameOptionsFilter" />
     <bean id="oauth2TokenParseFilter" class="java.lang.Class" factory-method="forName">
@@ -68,7 +68,7 @@
         </property>
         <property name="ignore">
             <list>
-                <value>healthz</value>
+                <value>secFilterOpen05Healthz</value>
             </list>
         </property>
         <property name="errorMap">
@@ -184,19 +184,19 @@
     <bean id="uiRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.DelegatingRequestMatcher">
         <constructor-arg>
             <list>
-                <bean class="org.springframework.security.web.util.AntPathRequestMatcher">
+                <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                     <constructor-arg value="/" />
                 </bean>
-                <bean class="org.springframework.security.web.util.AntPathRequestMatcher">
+                <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                     <constructor-arg value="/spring_security_login" />
                 </bean>
-                <bean class="org.springframework.security.web.util.AntPathRequestMatcher">
+                <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                     <constructor-arg value="/oauth/**" />
                 </bean>
-                <bean class="org.springframework.security.web.util.AntPathRequestMatcher">
+                <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                     <constructor-arg value="/login**" />
                 </bean>
-                <bean class="org.springframework.security.web.util.AntPathRequestMatcher">
+                <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
                     <constructor-arg value="/logout.do*" />
                 </bean>
             </list>
diff --git a/uaa/src/main/webapp/WEB-INF/spring/approvals-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/approvals-endpoints.xml
index 51d7a5b6af4..c01435c4434 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/approvals-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/approvals-endpoints.xml
@@ -16,9 +16,9 @@
     xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
     xmlns:util="http://www.springframework.org/schema/util"
     xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
 
     <sec:global-method-security pre-post-annotations="enabled" />
 
@@ -50,11 +50,12 @@
     </bean>
 
     <http name="approvalsSecurity" pattern="/approvals/**" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"  use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="scope=oauth.approvals" />
         <custom-filter ref="approvalsResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <oauth:resource-server id="approvalsResourceAuthenticationFilter" token-services-ref="tokenServices"
diff --git a/uaa/src/main/webapp/WEB-INF/spring/client-admin-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/client-admin-endpoints.xml
index 84f9d62e271..6acc488345d 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/client-admin-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/client-admin-endpoints.xml
@@ -15,16 +15,17 @@
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
     xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
-		http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
+        http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
     <http name="clientSecretSecurity" pattern="/oauth/clients/*/secret" create-session="stateless"
-        authentication-manager-ref="emptyAuthenticationManager" entry-point-ref="oauthAuthenticationEntryPoint"
+        authentication-manager-ref="emptyAuthenticationManager" entry-point-ref="oauthAuthenticationEntryPoint"  use-expressions="false"
         access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/oauth/clients/*/secret" access="IS_AUTHENTICATED_FULLY,scope=clients.secret" />
         <custom-filter ref="oauthWithoutResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <http name="clientTxAdminSecurity" pattern="/oauth/clients/tx/**" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
@@ -35,6 +36,7 @@
         <custom-filter ref="oauthWithoutResourceAuthenticationFilter" before="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
         <expression-handler ref="oauthWebExpressionHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <http name="clientAdminSecurity" pattern="/oauth/clients/**" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
@@ -46,6 +48,7 @@
         <custom-filter ref="oauthWithoutResourceAuthenticationFilter" before="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
         <expression-handler ref="oauthWebExpressionHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <oauth:resource-server id="clientResourceAuthenticationFilter" token-services-ref="tokenServices"
@@ -75,7 +78,7 @@
         </property>
         <property name="clientDetailsValidator" ref="clientDetailsValidator"/>
     </bean>
-    
+
     <bean id="clientDetailsValidator" class="org.cloudfoundry.identity.uaa.oauth.ClientAdminEndpointsValidator">
         <property name="clientDetailsService" ref="clientDetailsService" />
     </bean>
diff --git a/uaa/src/main/webapp/WEB-INF/spring/codestore-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/codestore-endpoints.xml
index f6c7aac8d7a..5d8c6e80d05 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/codestore-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/codestore-endpoints.xml
@@ -1,11 +1,20 @@
-<?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:security="http://www.springframework.org/schema/security"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-       http://www.springframework.org/schema/beans/spring-beans.xsd
-       http://www.springframework.org/schema/security
-       http://www.springframework.org/schema/security/spring-security.xsd">
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+    Cloud Foundry
+    Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
+
+    This product is licensed to you under the Apache License, Version 2.0 (the "License").
+    You may not use this product except in compliance with the License.
+
+    This product includes a number of subcomponents with
+    separate copyright notices and license terms. Your use of these
+    subcomponents is subject to the terms and conditions of the
+    subcomponent's license, as noted in the LICENSE file.
+
+-->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
+       xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
     <bean id="codeStoreEndpoints" class="org.cloudfoundry.identity.uaa.codestore.CodeStoreEndpoints">
         <property name="expiringCodeStore" ref="codeStore" />
@@ -15,10 +24,11 @@
     </bean>
 
     <http create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
-          access-decision-manager-ref="userAccessDecisionManager" pattern="/Codes/**" xmlns="http://www.springframework.org/schema/security">
+          access-decision-manager-ref="userAccessDecisionManager" pattern="/Codes/**" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="scope=scim.create,scope=scim.write,scope=password.write" />
         <custom-filter ref="resourceAgnosticAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 </beans>
\ No newline at end of file
diff --git a/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml b/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
index 19e8913c028..5db433ceceb 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/login-server-security.xml
@@ -16,21 +16,22 @@
     xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
     xmlns:util="http://www.springframework.org/schema/util"
     xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
-        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
 
     <oauth:resource-server id="oauthResourceAuthenticationFilter" token-services-ref="tokenServices"
         resource-id="oauth" entry-point-ref="oauthAuthenticationEntryPoint" />
 
-    <http request-matcher-ref="loginAuthenticateRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
-          authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerAuthenticate" request-matcher-ref="loginAuthenticateRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
+          authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <!-- scope authentication filter configured with a scope authentication manager -->
         <custom-filter ref="oauthLoginScopeAuthenticatingFilter" after="PRE_AUTH_FILTER"/>
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="loginAuthenticateRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
@@ -43,10 +44,10 @@
         </property>
     </bean>
 
-    <sec:http pattern="/authenticate/**" security="none" />
+    <sec:http name="secFilterAuthenticateOpen"  pattern="/authenticate/**" security="none" />
 
-    <http request-matcher-ref="loginAuthorizeRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
-        authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerAuthorize" request-matcher-ref="loginAuthorizeRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
+        authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
         <custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
@@ -55,6 +56,7 @@
         <custom-filter ref="loginAuthenticationFilter" position="FORM_LOGIN_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="loginAuthorizeRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
@@ -67,8 +69,8 @@
         </property>
     </bean>
 
-    <http request-matcher-ref="loginTokenRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
-          authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerToken" request-matcher-ref="loginTokenRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
+          authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <!--
           This represents a /oauth/token requests that gets passed through
           from the login server. It assumes that the User has been authenticated
@@ -92,6 +94,7 @@
         <custom-filter ref="loginServerTokenEndpointAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="oauthLoginScopeAuthenticatingFilter" class="org.cloudfoundry.identity.uaa.authentication.manager.ScopeAuthenticationFilter">
@@ -137,14 +140,15 @@
 
 
     <!-- Support for older login servers -->
-    <http request-matcher-ref="loginAuthorizeRequestMatcherOld" create-session="always" entry-point-ref="oauthAuthenticationEntryPoint"
-        authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerAuthorizeOld" request-matcher-ref="loginAuthorizeRequestMatcherOld" create-session="always" entry-point-ref="oauthAuthenticationEntryPoint"
+        authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
         <custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <custom-filter ref="loginAuthenticationFilter" position="FORM_LOGIN_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="loginAuthorizeRequestMatcherOld" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
@@ -197,19 +201,21 @@
         <constructor-arg ref="clientDetailsService"/>
     </bean>
 
-    <http create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
-        access-decision-manager-ref="accessDecisionManager" pattern="/password_*" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerPasswordEndpoints" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
+        access-decision-manager-ref="accessDecisionManager" pattern="/password_*" xmlns="http://www.springframework.org/schema/security"  use-expressions="false">
         <intercept-url pattern="/**" access="scope=oauth.login" />
         <custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
-    <http create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
-          access-decision-manager-ref="accessDecisionManager" pattern="/email_*" xmlns="http://www.springframework.org/schema/security">
+    <http name="secFilterLoginServerEmailEndpoints" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
+          access-decision-manager-ref="accessDecisionManager" pattern="/email_*" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="scope=oauth.login" />
         <custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 </beans>
diff --git a/uaa/src/main/webapp/WEB-INF/spring/multitenant-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/multitenant-endpoints.xml
index ff5dc35ed17..597d4758dd2 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/multitenant-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/multitenant-endpoints.xml
@@ -1,6 +1,6 @@
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
        xmlns:aop="http://www.springframework.org/schema/aop"
-       xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+       xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
 
@@ -57,6 +57,7 @@
         <custom-filter ref="resourceAgnosticAuthenticationFilter" before="PRE_AUTH_FILTER"/>
         <access-denied-handler ref="oauthAccessDeniedHandler"/>
         <expression-handler ref="oauthWebExpressionHandler"/>
+        <csrf disabled="true"/>
     </http>
 
 
@@ -115,6 +116,7 @@
                        method="GET"/>
         <custom-filter ref="resourceAgnosticAuthenticationFilter" before="PRE_AUTH_FILTER"/>
         <expression-handler ref="oauthWebExpressionHandler"/>
+        <csrf disabled="true"/>
     </http>
 
     <bean id="idpEventPublisher" class="org.cloudfoundry.identity.uaa.zone.event.IdentityProviderEventPublisher"/>
diff --git a/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
index 49ad5fd29b5..9d25ddd3604 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/oauth-endpoints.xml
@@ -16,10 +16,10 @@
     xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:util="http://www.springframework.org/schema/util"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
-		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
+        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
 
     <!--<bean id="tokenEndpoint" class="org.springframework.security.oauth2.provider.endpoint.TokenEndpoint" autowire="byType">-->
         <!--<property name="OAuth2RequestValidator">-->
@@ -43,7 +43,7 @@
 
     <!-- Owner password flow for external authentication (SAML) -->
     <!-- Pattern: /oauth/token parameters:{grant_type=password,passcode= -->
-    <http name="tokenEndpointSecurityForPasscodes" request-matcher-ref="passcodeTokenMatcher" create-session="stateless"
+    <http name="tokenEndpointSecurityForPasscodes" request-matcher-ref="passcodeTokenMatcher" create-session="stateless" use-expressions="false"
           entry-point-ref="basicAuthenticationEntryPoint" xmlns="http://www.springframework.org/schema/security"  authentication-manager-ref="emptyAuthenticationManager">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <anonymous enabled="false" />
@@ -51,6 +51,7 @@
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
         <custom-filter ref="passcodeAuthenticationFilter" after="BASIC_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="passcodeAuthenticationFilter" class="org.cloudfoundry.identity.uaa.login.PasscodeAuthenticationFilter">
@@ -98,7 +99,7 @@
     </bean>
 
     <!--/oauth/token with any match -->
-    <http name="tokenEndpointSecurity" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
+    <http name="tokenEndpointSecurity" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" use-expressions="false"
         pattern="/oauth/token/**" entry-point-ref="basicAuthenticationEntryPoint" xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <anonymous enabled="false" />
@@ -106,6 +107,7 @@
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
         <custom-filter ref="tokenEndpointAuthenticationFilter" after="BASIC_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <!-- Version of the /authorize endpoint for stateless clients such as cf
@@ -113,12 +115,13 @@
     -->
     <http name="statelessAuthzEndpointSecurity" request-matcher-ref="oauthAuthorizeRequestMatcher" create-session="stateless"
         entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="zoneAwareAuthzAuthenticationManager"
-        xmlns="http://www.springframework.org/schema/security">
+        xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
         <custom-filter ref="authzAuthenticationFilter" position="FORM_LOGIN_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="clientAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
@@ -194,12 +197,13 @@
     -->
     <http name="oldAuthzEndpointSecurity" request-matcher-ref="oauthAuthorizeRequestMatcherOld" create-session="stateless"
         entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="zoneAwareAuthzAuthenticationManager"
-        xmlns="http://www.springframework.org/schema/security">
+        xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
         <custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
         <custom-filter ref="authzAuthenticationFilter" position="FORM_LOGIN_FILTER" />
         <anonymous enabled="false" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="oauthAuthorizeRequestMatcherOld" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
diff --git a/uaa/src/main/webapp/WEB-INF/spring/openid-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/openid-endpoints.xml
index 2993d4380d7..d71d2cf95e7 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/openid-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/openid-endpoints.xml
@@ -15,15 +15,16 @@
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
     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-2.0.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
     <http name="userInfoSecurity" pattern="/userinfo" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"  use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="scope=openid" />
         <custom-filter ref="openidResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <oauth:resource-server id="openidResourceAuthenticationFilter" token-services-ref="tokenServices"
diff --git a/uaa/src/main/webapp/WEB-INF/spring/resource-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/resource-endpoints.xml
index 72a55746cc5..ddb56f72cb2 100755
--- a/uaa/src/main/webapp/WEB-INF/spring/resource-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/resource-endpoints.xml
@@ -13,25 +13,27 @@
 
 -->
 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
-    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
+    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
 		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
     <http name="checkTokenSecurity" pattern="/check_token" create-session="stateless" entry-point-ref="basicAuthenticationEntryPoint"
         authentication-manager-ref="clientAuthenticationManager" use-expressions="true"
         xmlns="http://www.springframework.org/schema/security">
-        <intercept-url pattern="/**" access="hasRole('uaa.resource')" />
+        <intercept-url pattern="/**" access="hasAuthority('uaa.resource')" />
         <anonymous enabled="false" />
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <http name="tokenKeySecurity" pattern="/token_key" create-session="stateless" entry-point-ref="basicAuthenticationEntryPoint"
         authentication-manager-ref="clientAuthenticationManager" use-expressions="true"
         xmlns="http://www.springframework.org/schema/security">
-        <intercept-url pattern="/**" access="isAnonymous() or hasRole('uaa.resource')" />
+        <intercept-url pattern="/**" access="isAnonymous() or hasAuthority('uaa.resource')" />
         <anonymous enabled="true" />
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <http name="clientInfoSecurity" pattern="/clientinfo" create-session="stateless" entry-point-ref="basicAuthenticationEntryPoint"
@@ -41,6 +43,7 @@
         <anonymous enabled="false" />
         <custom-filter ref="clientAuthenticationFilter" position="BASIC_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="checkTokenEndpoint" class="org.cloudfoundry.identity.uaa.oauth.CheckTokenEndpoint">
diff --git a/uaa/src/main/webapp/WEB-INF/spring/saml-providers.xml b/uaa/src/main/webapp/WEB-INF/spring/saml-providers.xml
index f0d59c6d29b..7106edccb19 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/saml-providers.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/saml-providers.xml
@@ -13,16 +13,11 @@
 
 -->
 
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
-       xmlns:cache="http://www.springframework.org/schema/cache"
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:security="http://www.springframework.org/schema/security"
+       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-4.0.xsd
-              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
-              http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
-              http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
-              http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
+              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
 
 
         <!-- Register authentication manager with SAML provider -->
@@ -31,7 +26,7 @@
         </security:authentication-manager>
 
         <bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
-            <security:filter-chain-map path-type="ant">
+            <security:filter-chain-map request-matcher="ant">
                 <security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint" />
                 <security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter" />
                 <security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter" />
diff --git a/uaa/src/main/webapp/WEB-INF/spring/scim-endpoints.xml b/uaa/src/main/webapp/WEB-INF/spring/scim-endpoints.xml
index 954692cc7fd..c2ecedbbb3d 100644
--- a/uaa/src/main/webapp/WEB-INF/spring/scim-endpoints.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring/scim-endpoints.xml
@@ -16,10 +16,10 @@
     xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:util="http://www.springframework.org/schema/util"
     xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
-		http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
+        http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
+        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
 
     <bean id="scimUserProvisioning" class="org.cloudfoundry.identity.uaa.scim.jdbc.JdbcScimUserProvisioning">
         <constructor-arg ref="jdbcTemplate" />
@@ -144,21 +144,23 @@
         </constructor-arg>
     </bean>
 
-    <http request-matcher-ref="groupsUpdateRequestMatcher" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="groupAccessDecisionManager"
+    <http name="scimGroupUpdate" request-matcher-ref="groupsUpdateRequestMatcher" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="groupAccessDecisionManager" use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="scope=scim.write,scope=groups.update,memberScope=writer"
             method="PUT" />
         <custom-filter ref="scimResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
-    <http request-matcher-ref="groupsReadRequestMatcher" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="groupAccessDecisionManager"
+    <http name="scimGroupRead" request-matcher-ref="groupsReadRequestMatcher" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="groupAccessDecisionManager" use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="scope=scim.read,memberScope=reader" method="GET" />
         <custom-filter ref="scimResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="groupsUpdateRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
@@ -184,6 +186,7 @@
         <custom-filter ref="scimResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
         <expression-handler ref="oauthWebExpressionHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="userIdsEnabled" class="java.lang.Boolean">
@@ -213,12 +216,13 @@
         </aop:aspect>
     </aop:config>
 
-    <http pattern="/User*/*/password" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
+    <http name="scimUserPassword" pattern="/User*/*/password" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"  use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/User*/*/password" access="IS_AUTHENTICATED_FULLY,scope=password.write" />
         <custom-filter ref="passwordResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <bean id="userAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
@@ -235,9 +239,9 @@
         </constructor-arg>
     </bean>
 
-    <http pattern="/Users/**" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
+    <http  name="scimUsers" pattern="/Users/**" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
         entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="userAccessDecisionManager"
-        xmlns="http://www.springframework.org/schema/security">
+        xmlns="http://www.springframework.org/schema/security" use-expressions="false">
         <intercept-url pattern="/Users/*/verify" access="scope=scim.write,scope=scim.create" method="GET" />
         <intercept-url pattern="/Users/**" access="scope=scim.read,user=self" method="GET" />
         <intercept-url pattern="/Users/*" access="scope=scim.write" method="DELETE" />
@@ -246,14 +250,16 @@
         <intercept-url pattern="/**" access="ROLE_NONEXISTENT" />
         <custom-filter ref="scimResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
-    <http pattern="/ids/Users*" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
-        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager"
+    <http  name="scimUserIds" pattern="/ids/Users*" create-session="stateless" authentication-manager-ref="emptyAuthenticationManager"
+        entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" use-expressions="false"
         xmlns="http://www.springframework.org/schema/security">
         <intercept-url pattern="/**" access="scope=scim.userids" />
         <custom-filter ref="idsResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
         <access-denied-handler ref="oauthAccessDeniedHandler" />
+        <csrf disabled="true"/>
     </http>
 
     <oauth:resource-server id="passwordResourceAuthenticationFilter" token-services-ref="tokenServices"
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/NativeApplicationIntegrationTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/NativeApplicationIntegrationTests.java
index 6527683b538..d9dd42d4d69 100755
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/NativeApplicationIntegrationTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/NativeApplicationIntegrationTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -75,7 +75,7 @@ public void testHappyDay() throws Exception {
         headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
         ResponseEntity<String> response = serverRunning.postForString("/oauth/token", formData, headers);
         assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
+        assertEquals("no-cache, no-store, max-age=0, must-revalidate", response.getHeaders().getFirst("Cache-Control"));
     }
 
     /**
@@ -101,11 +101,14 @@ public void testInvalidClient() throws Exception {
         if (newCookies != null && !newCookies.isEmpty()) {
             fail("No cookies should be set. Found: " + newCookies.get(0) + ".");
         }
-        assertEquals("no-store", response.getHeaders().getFirst("Cache-Control"));
+        assertEquals("no-cache, no-store, max-age=0, must-revalidate", response.getHeaders().getFirst("Cache-Control"));
+
+        assertEquals(401, response.getStatusCode().value());
 
         @SuppressWarnings("unchecked")
         OAuth2Exception error = OAuth2Exception.valueOf(response.getBody());
-        assertEquals("invalid_client", error.getOAuth2ErrorCode());
+        assertEquals("Bad credentials", error.getMessage());
+        assertEquals("invalid_request", error.getOAuth2ErrorCode());
     }
 
     /**
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/RefreshTokenSupportIntegrationTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/RefreshTokenSupportIntegrationTests.java
index 6f91a0f77c1..f2d3b3378cb 100755
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/RefreshTokenSupportIntegrationTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/RefreshTokenSupportIntegrationTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -139,7 +139,7 @@ public void testTokenRefreshedCorrectFlow() throws Exception {
         formData.add("refresh_token", accessToken.getRefreshToken().getValue());
         tokenResponse = serverRunning.postForMap("/oauth/token", formData, tokenHeaders);
         assertEquals(HttpStatus.OK, tokenResponse.getStatusCode());
-        assertEquals("no-store", tokenResponse.getHeaders().getFirst("Cache-Control"));
+        assertEquals("no-cache, no-store, max-age=0, must-revalidate", tokenResponse.getHeaders().getFirst("Cache-Control"));
         @SuppressWarnings("unchecked")
         OAuth2AccessToken newAccessToken = DefaultOAuth2AccessToken.valueOf(tokenResponse.getBody());
         try {
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
index 8e277ebbaaf..02fe6464763 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenKeyEndpointMockMvcTests.java
@@ -37,6 +37,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 public class TokenKeyEndpointMockMvcTests extends TestClassNullifier {
@@ -121,11 +122,29 @@ public void checkTokenKeyValues() throws Exception {
             get("/token_key")
                 .accept(MediaType.APPLICATION_JSON)
                 .header("Authorization", basicDigestHeaderValue))
+            .andDo(print())
             .andExpect(status().isOk())
             .andReturn();
 
-        Map<String,Object> key = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
+        Map<String, Object> key = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
+        validateKey(key);
+    }
+
+    @Test
+    public void checkTokenKeyValuesAnonymous() throws Exception {
+
+        MvcResult result = mockMvc.perform(
+            get("/token_key")
+                .accept(MediaType.APPLICATION_JSON))
+            .andDo(print())
+            .andExpect(status().isOk())
+            .andReturn();
+
+        Map<String, Object> key = JsonUtils.readValue(result.getResponse().getContentAsString(), Map.class);
+        validateKey(key);
+    }
 
+    public void validateKey(Map<String,Object> key) {
         Object kty = key.get("kty");
         assertNotNull(kty);
         assertTrue(kty instanceof String);
diff --git a/uaa/src/test/resources/test-security.xml b/uaa/src/test/resources/test-security.xml
index a8cd2b110a0..e7acfe1a6d6 100755
--- a/uaa/src/test/resources/test-security.xml
+++ b/uaa/src/test/resources/test-security.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!--
-    Cloud Foundry 
+    Cloud Foundry
     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
 
     This product is licensed to you under the Apache License, Version 2.0 (the "License").

From dcdc82b5e62e267234284646440525dc61b537d6 Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Wed, 6 May 2015 07:59:56 -0600
Subject: [PATCH 4/9] Remove print() statements to reduce log output

---
 .../uaa/login/AccountsControllerMockMvcTests.java    |  4 ----
 .../identity/uaa/login/PasscodeMockMvcTests.java     |  8 +-------
 .../identity/uaa/mock/ldap/LdapMockMvcTests.java     |  2 --
 .../identity/uaa/mock/token/TokenMvcMockTests.java   | 12 ++++--------
 .../identity/uaa/mock/util/MockMvcUtils.java         |  2 +-
 .../endpoints/ScimGroupEndpointsMockMvcTests.java    |  1 -
 .../scim/endpoints/ScimUserLookupMockMvcTests.java   |  1 -
 .../cloudfoundry/identity/uaa/test/TestClient.java   |  1 +
 8 files changed, 7 insertions(+), 24 deletions(-)

diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
index ed67ec27b17..8007ce07d9d 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/AccountsControllerMockMvcTests.java
@@ -162,7 +162,6 @@ public void testCreatingAnAccount() throws Exception {
 
         MvcResult mvcResult = mockMvc.perform(get("/verify_user")
                 .param("code", "test"+generator.counter.get()))
-                .andDo(print())
                 .andExpect(status().isFound())
                 .andExpect(redirectedUrl("home"))
                 .andReturn();
@@ -191,7 +190,6 @@ public void testCreatingAnAccountWithAnEmptyClientId() throws Exception {
 
         MvcResult mvcResult = mockMvc.perform(get("/verify_user")
                 .param("code", "test"+generator.counter.get()))
-                .andDo(print())
                 .andExpect(status().isFound())
                 .andExpect(redirectedUrl("home"))
                 .andReturn();
@@ -225,7 +223,6 @@ public void testCreatingAnAccountWithClientRedirect() throws Exception {
 
         MvcResult mvcResult = mockMvc.perform(get("/verify_user")
                 .param("code", "test"+generator.counter.get()))
-            .andDo(print())
             .andExpect(status().isFound())
             .andExpect(redirectedUrl("http://localhost:8080/app/"))
             .andReturn();
@@ -329,7 +326,6 @@ public void testCreatingAnAccountInAnotherZoneWithClientRedirect() throws Except
         MvcResult mvcResult = mockMvc.perform(get("/verify_user")
                     .param("code", "test" + generator.counter.get())
                     .with(new SetServerNameRequestPostProcessor("mysubdomain.localhost")))
-                .andDo(print())
                 .andExpect(status().isFound())
                 .andExpect(redirectedUrl("http://myzoneclient.example.com"))
                 .andReturn();
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
index 1cc761ffa2b..28dcf2126ee 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/PasscodeMockMvcTests.java
@@ -135,7 +135,6 @@ public void testLoginUsingPasscodeWithSamlToken() throws Exception {
         String passcode = JsonUtils.readValue(
             mockMvc.perform(get)
                 .andExpect(status().isOk())
-                .andDo(print())
                 .andReturn().getResponse().getContentAsString(),
             String.class);
 
@@ -160,7 +159,6 @@ public void testLoginUsingPasscodeWithSamlToken() throws Exception {
         Map accessToken =
             JsonUtils.readValue(
                 mockMvc.perform(post)
-                    .andDo(print())
                     .andExpect(status().isOk())
                     .andReturn().getResponse().getContentAsString(),
                 Map.class);
@@ -202,7 +200,6 @@ public void testLoginUsingPasscodeWithUaaToken() throws Exception {
         String passcode = JsonUtils.readValue(
             mockMvc.perform(get)
                 .andExpect(status().isOk())
-                .andDo(print())
                 .andReturn().getResponse().getContentAsString(),
             String.class);
 
@@ -227,7 +224,6 @@ public void testLoginUsingPasscodeWithUaaToken() throws Exception {
         Map accessToken =
             JsonUtils.readValue(
                 mockMvc.perform(post)
-                    .andDo(print())
                     .andExpect(status().isOk())
                     .andReturn().getResponse().getContentAsString(),
                 Map.class);
@@ -270,9 +266,7 @@ public void testLoginUsingPasscodeWithUnknownToken() throws Exception {
             .session(session);
 
         mockMvc.perform(get)
-            .andExpect(status().isForbidden())
-            .andDo(print());
-
+            .andExpect(status().isForbidden());
     }
 
     public static class MockSecurityContext implements SecurityContext {
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java
index d0504c13001..9d914513f79 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/ldap/LdapMockMvcTests.java
@@ -263,7 +263,6 @@ public void testLdapConfigurationBeforeSave() throws Exception {
             .header(IdentityZoneSwitchingFilter.HEADER, zone.getId());
 
         MvcResult result = mockMvc.perform(post)
-            .andDo(print())
             .andExpect(status().isOk())
             .andReturn();
 
@@ -619,7 +618,6 @@ public void testLogin() throws Exception {
         mockMvc.perform(post("/login.do").accept(TEXT_HTML_VALUE)
                         .param("username", "marissa2")
                         .param("password", "ldap"))
-            .andDo(print())
                 .andExpect(status().isFound())
                 .andExpect(redirectedUrl("/"));
     }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
index cae04c40fbe..40d0cc81766 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/token/TokenMvcMockTests.java
@@ -285,7 +285,6 @@ public void testClientIdentityProviderWithoutAllowedProvidersForPasswordGrantWor
             .param(OAuth2Utils.RESPONSE_TYPE,"token")
             .param(OAuth2Utils.GRANT_TYPE, "password")
             .param(OAuth2Utils.CLIENT_ID, clientId))
-            .andDo(print())
             .andExpect(status().isOk());
 
         mockMvc.perform(post("/oauth/token")
@@ -296,7 +295,6 @@ public void testClientIdentityProviderWithoutAllowedProvidersForPasswordGrantWor
             .param(OAuth2Utils.RESPONSE_TYPE,"token")
             .param(OAuth2Utils.GRANT_TYPE, "password")
             .param(OAuth2Utils.CLIENT_ID, clientId2))
-            .andDo(print())
             .andExpect(status().isOk());
 
 
@@ -347,7 +345,7 @@ public void testClientIdentityProviderClientWithoutAllowedProvidersForAuthCodeAl
             .param(OAuth2Utils.STATE, state)
             .param(OAuth2Utils.CLIENT_ID, clientId)
             .param(OAuth2Utils.REDIRECT_URI, TEST_REDIRECT_URI))
-            .andDo(print()).andExpect(status().isFound());
+            .andExpect(status().isFound());
 
         //correct provider is ok
         MvcResult result = mockMvc.perform(get("/oauth/authorize")
@@ -357,7 +355,7 @@ public void testClientIdentityProviderClientWithoutAllowedProvidersForAuthCodeAl
             .param(OAuth2Utils.STATE, state)
             .param(OAuth2Utils.CLIENT_ID, clientId2)
             .param(OAuth2Utils.REDIRECT_URI, TEST_REDIRECT_URI))
-            .andDo(print()).andExpect(status().isFound())
+            .andExpect(status().isFound())
             .andReturn();
 
         //other provider, not ok
@@ -368,7 +366,7 @@ public void testClientIdentityProviderClientWithoutAllowedProvidersForAuthCodeAl
             .param(OAuth2Utils.STATE, state)
             .param(OAuth2Utils.CLIENT_ID, clientId3)
             .param(OAuth2Utils.REDIRECT_URI, TEST_REDIRECT_URI))
-            .andDo(print()).andExpect(status().isUnauthorized())
+            .andExpect(status().isUnauthorized())
             .andExpect(model().attributeExists("error"))
             .andExpect(model().attribute("error_message_code","login.invalid_idp"));
 
@@ -407,7 +405,6 @@ public void testClientIdentityProviderRestrictionForPasswordGrant() throws Excep
             .param(OAuth2Utils.RESPONSE_TYPE,"token")
             .param(OAuth2Utils.GRANT_TYPE, "password")
             .param(OAuth2Utils.CLIENT_ID, clientId))
-            .andDo(print())
             .andExpect(status().isUnauthorized());
 
         mockMvc.perform(post("/oauth/token")
@@ -417,7 +414,6 @@ public void testClientIdentityProviderRestrictionForPasswordGrant() throws Excep
             .param(OAuth2Utils.RESPONSE_TYPE, "token")
             .param(OAuth2Utils.GRANT_TYPE, "password")
             .param(OAuth2Utils.CLIENT_ID, clientId2))
-            .andDo(print())
             .andExpect(status().isOk());
     }
 
@@ -1669,7 +1665,7 @@ public void testGetTokenScopesNotInAuthentication() throws Exception {
             .param("code", code)
             .param(OAuth2Utils.CLIENT_ID, "identity")
             .param(OAuth2Utils.REDIRECT_URI, "http://localhost/test");
-        result = mockMvc.perform(authRequest).andDo(print()).andExpect(status().is2xxSuccessful()).andReturn();
+        result = mockMvc.perform(authRequest).andExpect(status().is2xxSuccessful()).andReturn();
         TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(), TestClient.OAuthToken.class);
 
         OAuth2Authentication a1 = tokenServices.loadAuthentication(oauthToken.accessToken);
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
index c19fed6cd13..ece9e54421b 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
@@ -373,7 +373,7 @@ public String getUserOAuthAccessTokenAuthCode(MockMvc mockMvc, String clientId,
                 .param("code", code)
                 .param(OAuth2Utils.CLIENT_ID, clientId)
                 .param(OAuth2Utils.REDIRECT_URI, "http://localhost/test");
-        result = mockMvc.perform(authRequest).andDo(print()).andExpect(status().is2xxSuccessful()).andReturn();
+        result = mockMvc.perform(authRequest).andExpect(status().is2xxSuccessful()).andReturn();
         TestClient.OAuthToken oauthToken = JsonUtils.readValue(result.getResponse().getContentAsString(),
             TestClient.OAuthToken.class);
         return oauthToken.accessToken;
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
index 5bf4373a8ae..c8e227cdadd 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsMockMvcTests.java
@@ -152,7 +152,6 @@ public void testIdentityClientManagesZoneAdmins() throws Exception {
             .content(JsonUtils.writeValueAsBytes(group));
         //create the zones.{id}.admin
         mockMvc.perform(post)
-            .andDo(print())
             .andExpect(status().isCreated());
         //it is already created
         mockMvc.perform(post)
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
index d483b4a9f1f..de84ba394ce 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimUserLookupMockMvcTests.java
@@ -116,7 +116,6 @@ public void testLookupUsingOnlyOrigin() throws Exception {
             .param("count", String.valueOf(50));
 
         mockMvc.perform(post)
-            .andDo(print())
             .andExpect(status().isBadRequest());
 
     }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
index a3615675591..b2f152d5e1e 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/test/TestClient.java
@@ -22,6 +22,7 @@
 import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
 
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 public class TestClient {

From 6944cc03b7de4e94147633bd1d9f5ad50a7b0352 Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Wed, 6 May 2015 15:06:43 -0600
Subject: [PATCH 5/9] Added CSRF protection just to /change_email end points

---
 login/src/main/resources/login-ui.xml         |  15 +-
 .../identity/uaa/login/LoginMockMvcTests.java | 134 +++++++++++++++++-
 2 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/login/src/main/resources/login-ui.xml b/login/src/main/resources/login-ui.xml
index 4226b60c2ee..0bc9d3358d7 100644
--- a/login/src/main/resources/login-ui.xml
+++ b/login/src/main/resources/login-ui.xml
@@ -61,13 +61,26 @@
 
     <bean id="backwardsCompatibleScopeParameter" class="org.cloudfoundry.identity.uaa.oauth.BackwardsCompatibleScopeParsingFilter"/>
 
+    <http name="changeEmailSecurity"
+          use-expressions="false"
+          pattern="/change_email**"
+          xmlns="http://www.springframework.org/schema/security">
+        <access-denied-handler error-page="/"/>
+        <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
+        <form-login login-page="/login" username-parameter="username" password-parameter="password"
+                    login-processing-url="/login.do" authentication-failure-handler-ref="loginAuthenticationFailureHandler"
+                    authentication-details-source-ref="authenticationDetailsSource"/>
+        <csrf disabled="false"/>
+    </http>
+
     <http name="uiSecurity" request-matcher-ref="uiRequestMatcher" use-expressions="false"
           authentication-manager-ref="zoneAwareAuthzAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
       <access-denied-handler error-page="/"/>
       <intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
       <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
       <form-login login-page="/login" username-parameter="username" password-parameter="password"
-                           login-processing-url="/login.do" authentication-failure-handler-ref="loginAuthenticationFailureHandler" authentication-details-source-ref="authenticationDetailsSource"/>
+                  login-processing-url="/login.do" authentication-failure-handler-ref="loginAuthenticationFailureHandler"
+                  authentication-details-source-ref="authenticationDetailsSource"/>
       <logout logout-url="/logout.do" success-handler-ref="logoutHandler" />
       <csrf disabled="true"/>
     </http>
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
index 3bb26c81dec..1b4c8df9b7d 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
@@ -35,6 +35,7 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.mock.env.MockEnvironment;
@@ -49,6 +50,8 @@
 import org.springframework.security.web.FilterChainProxy;
 import org.springframework.security.web.PortResolverImpl;
 import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
+import org.springframework.security.web.csrf.CsrfToken;
+import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
 import org.springframework.security.web.savedrequest.DefaultSavedRequest;
 import org.springframework.security.web.savedrequest.SavedRequest;
 import org.springframework.test.web.servlet.MockMvc;
@@ -66,13 +69,17 @@
 import java.util.Locale;
 import java.util.Map;
 
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasEntry;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertNotNull;
 import static org.springframework.http.MediaType.APPLICATION_JSON;
 import static org.springframework.http.MediaType.TEXT_HTML;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
@@ -454,7 +461,7 @@ public String[] getParameterValues(String name) {
             .session(session)
             .with(new SetServerNameRequestPostProcessor(identityZone.getSubdomain() + ".localhost")))
             .andExpect(status().isFound())
-            .andExpect(redirectedUrl("saml/discovery?returnIDParam=idp&entityID="+identityZone.getSubdomain()+".cloudfoundry-saml-login&idp=active-saml&isPassive=true"));
+            .andExpect(redirectedUrl("saml/discovery?returnIDParam=idp&entityID=" + identityZone.getSubdomain() + ".cloudfoundry-saml-login&idp=active-saml&isPassive=true"));
     }
 
     @Test
@@ -487,4 +494,129 @@ public void testDeactivatedProviderIsRemovedFromSamlLoginLinks() throws Exceptio
             .andExpect(status().isOk())
             .andExpect(xpath("//a[text()='" + identityProviderDefinition.getLinkText() + "']").doesNotExist());
     }
+
+    @Test
+    public void testChangeEmailWithoutAuthenticationReturnsRedirect() throws Exception {
+        mockMvc.perform(get("/change_email").accept(TEXT_HTML))
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/login"));
+    }
+
+    @Test
+    public void testChangeEmailPageHasCsrf() throws Exception {
+        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
+        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
+        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
+        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
+        MockHttpSession session = new MockHttpSession();
+        SecurityContext securityContext = new SecurityContextImpl();
+        securityContext.setAuthentication(principal);
+        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+
+        MockHttpServletRequestBuilder get = get("/change_email")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal);
+        mockMvc.perform(get)
+            .andExpect(status().isOk())
+            .andExpect(content().string(containsString("_csrf")));
+        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
+    }
+
+    @Test
+    public void testChangeEmailSubmitWithMissingCsrf() throws Exception {
+        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
+        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
+        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
+        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
+        MockHttpSession session = new MockHttpSession();
+        SecurityContext securityContext = new SecurityContextImpl();
+        securityContext.setAuthentication(principal);
+        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+
+        MockHttpServletRequestBuilder get = get("/change_email")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal);
+        mockMvc.perform(get)
+            .andExpect(status().isOk())
+            .andExpect(content().string(containsString("_csrf")));
+        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
+
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal)
+            .param("newEmail", "test@test.org")
+            .param("client_id", "");
+        mockMvc.perform(changeEmail)
+            .andExpect(status().is4xxClientError());
+    }
+
+    @Test
+    public void testChangeEmailSubmitWithInvalidCsrf() throws Exception {
+        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
+        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
+        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
+        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
+        MockHttpSession session = new MockHttpSession();
+        SecurityContext securityContext = new SecurityContextImpl();
+        securityContext.setAuthentication(principal);
+        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+
+        MockHttpServletRequestBuilder get = get("/change_email")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal);
+        mockMvc.perform(get)
+            .andExpect(status().isOk())
+            .andExpect(content().string(containsString("_csrf")));
+        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
+
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal)
+            .param("newEmail", "test@test.org")
+            .param("client_id", "")
+            .param("_csrf", "invalid csrf token");
+        mockMvc.perform(changeEmail)
+            .andExpect(status().is4xxClientError());
+    }
+
+    @Test
+    public void testChangeEmailSubmitWithCorrectCsrf() throws Exception {
+        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
+        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
+        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
+        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
+        MockHttpSession session = new MockHttpSession();
+        SecurityContext securityContext = new SecurityContextImpl();
+        securityContext.setAuthentication(principal);
+        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+
+        MockHttpServletRequestBuilder get = get("/change_email")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal);
+        mockMvc.perform(get)
+            .andExpect(status().isOk())
+            .andExpect(content().string(containsString("_csrf")));
+        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
+        CsrfToken csrfToken = (CsrfToken)session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"));
+
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .session(session)
+            .principal(principal)
+            .param("newEmail", "test@test.org")
+            .param("client_id", "")
+            .param("_csrf", csrfToken.getToken());
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("email_sent?code=email_change"));
+
+    }
+
+
 }

From 062fce1a57b898ee67c668158fce239b5ba75107 Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Wed, 6 May 2015 15:39:03 -0600
Subject: [PATCH 6/9] Enhance tests with Spring Security Test helpers

---
 common/build.gradle                           |  1 +
 .../identity/uaa/login/LoginMockMvcTests.java | 96 +++++++++----------
 .../identity/uaa/mock/util/MockMvcUtils.java  | 15 ++-
 3 files changed, 60 insertions(+), 52 deletions(-)

diff --git a/common/build.gradle b/common/build.gradle
index de82dbb63f0..d13752fe49c 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -65,6 +65,7 @@ dependencies {
   testCompile group: 'postgresql', name: 'postgresql', version:parent.postgresqlVersion
   testCompile group: 'org.mockito', name: 'mockito-all', version:'1.8.5'
   testCompile group: 'org.apache.tomcat', name: 'tomcat-jdbc', version:parent.tomcatVersion
+  testCompile group: 'org.springframework.security', name: 'spring-security-test', version:parent.springSecurityVersion
 }
 
 apply from: file('build_properties.gradle')
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
index 1b4c8df9b7d..8d120ab5e4f 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
@@ -55,6 +55,7 @@
 import org.springframework.security.web.savedrequest.DefaultSavedRequest;
 import org.springframework.security.web.savedrequest.SavedRequest;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
 import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@@ -62,6 +63,7 @@
 import org.springframework.web.context.support.XmlWebApplicationContext;
 
 import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpSession;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -69,6 +71,7 @@
 import java.util.Locale;
 import java.util.Map;
 
+import static org.hamcrest.Matchers.any;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasEntry;
 import static org.hamcrest.Matchers.hasKey;
@@ -77,12 +80,15 @@
 import static org.junit.Assert.assertNotNull;
 import static org.springframework.http.MediaType.APPLICATION_JSON;
 import static org.springframework.http.MediaType.TEXT_HTML;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.securityContext;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
@@ -504,49 +510,33 @@ public void testChangeEmailWithoutAuthenticationReturnsRedirect() throws Excepti
 
     @Test
     public void testChangeEmailPageHasCsrf() throws Exception {
-        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
-        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
-        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
-        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
-        MockHttpSession session = new MockHttpSession();
-        SecurityContext securityContext = new SecurityContextImpl();
-        securityContext.setAuthentication(principal);
-        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
 
         MockHttpServletRequestBuilder get = get("/change_email")
             .accept(TEXT_HTML)
-            .session(session)
-            .principal(principal);
+            .with(securityContext(marissaContext));
         mockMvc.perform(get)
             .andExpect(status().isOk())
             .andExpect(content().string(containsString("_csrf")));
-        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
     }
 
     @Test
     public void testChangeEmailSubmitWithMissingCsrf() throws Exception {
-        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
-        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
-        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
-        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
-        MockHttpSession session = new MockHttpSession();
-        SecurityContext securityContext = new SecurityContextImpl();
-        securityContext.setAuthentication(principal);
-        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
 
         MockHttpServletRequestBuilder get = get("/change_email")
             .accept(TEXT_HTML)
-            .session(session)
-            .principal(principal);
-        mockMvc.perform(get)
+            .with(securityContext(marissaContext));
+        MockHttpSession session = (MockHttpSession)mockMvc.perform(get)
             .andExpect(status().isOk())
-            .andExpect(content().string(containsString("_csrf")));
+            .andExpect(content().string(containsString("_csrf")))
+            .andReturn().getRequest().getSession();
         assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
 
         MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
             .accept(TEXT_HTML)
             .session(session)
-            .principal(principal)
+            .with(securityContext(marissaContext))
             .param("newEmail", "test@test.org")
             .param("client_id", "");
         mockMvc.perform(changeEmail)
@@ -555,28 +545,21 @@ public void testChangeEmailSubmitWithMissingCsrf() throws Exception {
 
     @Test
     public void testChangeEmailSubmitWithInvalidCsrf() throws Exception {
-        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
-        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
-        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
-        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
-        MockHttpSession session = new MockHttpSession();
-        SecurityContext securityContext = new SecurityContextImpl();
-        securityContext.setAuthentication(principal);
-        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
 
         MockHttpServletRequestBuilder get = get("/change_email")
             .accept(TEXT_HTML)
-            .session(session)
-            .principal(principal);
-        mockMvc.perform(get)
+            .with(securityContext(marissaContext));
+        MockHttpSession session = (MockHttpSession)mockMvc.perform(get)
             .andExpect(status().isOk())
-            .andExpect(content().string(containsString("_csrf")));
+            .andExpect(content().string(containsString("_csrf")))
+            .andReturn().getRequest().getSession();
         assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
 
         MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
             .accept(TEXT_HTML)
             .session(session)
-            .principal(principal)
+            .with(securityContext(marissaContext))
             .param("newEmail", "test@test.org")
             .param("client_id", "")
             .param("_csrf", "invalid csrf token");
@@ -584,31 +567,42 @@ public void testChangeEmailSubmitWithInvalidCsrf() throws Exception {
             .andExpect(status().is4xxClientError());
     }
 
+    @Test
+    public void testChangeEmailSubmitWithSpringSecurityForcedCsrf() throws Exception {
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
+        //example shows to to test a request that is secured by csrf and you wish to bypass it
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .with(securityContext(marissaContext))
+            .with(csrf())
+            .param("newEmail", "test@test.org")
+            .param("client_id", "");
+
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("email_sent?code=email_change"));
+    }
+
     @Test
     public void testChangeEmailSubmitWithCorrectCsrf() throws Exception {
-        ScimUserProvisioning userProvisioning = webApplicationContext.getBean(JdbcScimUserProvisioning.class);
-        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
-        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
-        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
-        MockHttpSession session = new MockHttpSession();
-        SecurityContext securityContext = new SecurityContextImpl();
-        securityContext.setAuthentication(principal);
-        session.putValue("SPRING_SECURITY_CONTEXT", securityContext);
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
 
         MockHttpServletRequestBuilder get = get("/change_email")
             .accept(TEXT_HTML)
-            .session(session)
-            .principal(principal);
-        mockMvc.perform(get)
+            .with(securityContext(marissaContext));
+
+        MvcResult result = mockMvc.perform(get)
             .andExpect(status().isOk())
-            .andExpect(content().string(containsString("_csrf")));
-        assertNotNull(session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN")));
+            .andExpect(content().string(containsString("_csrf")))
+            .andReturn();
+
+        MockHttpSession session = (MockHttpSession)result.getRequest().getSession();
         CsrfToken csrfToken = (CsrfToken)session.getAttribute(HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"));
 
         MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
             .accept(TEXT_HTML)
+            .with(securityContext(marissaContext))
             .session(session)
-            .principal(principal)
             .param("newEmail", "test@test.org")
             .param("client_id", "")
             .param("_csrf", csrfToken.getToken());
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
index ece9e54421b..74037a050d7 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
@@ -22,6 +22,8 @@
 import org.cloudfoundry.identity.uaa.scim.ScimGroup;
 import org.cloudfoundry.identity.uaa.scim.ScimGroupMember;
 import org.cloudfoundry.identity.uaa.scim.ScimUser;
+import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
+import org.cloudfoundry.identity.uaa.scim.jdbc.JdbcScimUserProvisioning;
 import org.cloudfoundry.identity.uaa.test.TestApplicationEventListener;
 import org.cloudfoundry.identity.uaa.test.TestClient;
 import org.cloudfoundry.identity.uaa.test.TestClient.OAuthToken;
@@ -44,6 +46,7 @@
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.context.SecurityContextImpl;
 import org.springframework.security.oauth2.common.util.OAuth2Utils;
 import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
 import org.springframework.security.oauth2.provider.ClientDetails;
@@ -297,7 +300,7 @@ public String getZoneAdminToken(MockMvc mockMvc, String adminToken, String zoneI
         group.setMembers(Arrays.asList(new ScimGroupMember(user.getId())));
         MockMvcUtils.utils().createGroup(mockMvc, adminToken, group);
         return getUserOAuthAccessTokenAuthCode(mockMvc, "identity", "identitysecret", user.getId(), user.getUserName(),
-                "secret", group.getDisplayName());
+            "secret", group.getDisplayName());
     }
 
     public String getUserOAuthAccessToken(MockMvc mockMvc, String clientId, String clientSecret, String username,
@@ -399,6 +402,16 @@ public String getClientCredentialsOAuthAccessToken(MockMvc mockMvc, String usern
         return oauthToken.accessToken;
     }
 
+    public SecurityContext getMarissaSecurityContext(ApplicationContext context) {
+        ScimUserProvisioning userProvisioning = context.getBean(JdbcScimUserProvisioning.class);
+        ScimUser marissa = userProvisioning.query("username eq \"marissa\" and origin eq \"uaa\"").get(0);
+        UaaPrincipal uaaPrincipal = new UaaPrincipal(marissa.getId(), marissa.getUserName(), marissa.getPrimaryEmail(), marissa.getOrigin(), marissa.getExternalId(), IdentityZoneHolder.get().getId());
+        UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(uaaPrincipal, null, Arrays.asList(UaaAuthority.fromAuthorities("uaa.user")));
+        SecurityContext securityContext = new SecurityContextImpl();
+        securityContext.setAuthentication(principal);
+        return securityContext;
+    }
+
     public <T extends ApplicationEvent>  TestApplicationEventListener<T> addEventListener(ConfigurableApplicationContext applicationContext, Class<T> clazz) {
         TestApplicationEventListener<T> listener = TestApplicationEventListener.forEventClass(clazz);
         applicationContext.addApplicationListener(listener);

From 7903b9af8990e3dd024ab627cc4587f7cbeb348f Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Thu, 7 May 2015 10:48:17 -0600
Subject: [PATCH 7/9] Support whitelist URLs for the logout redirect parameter

---
 .../WhitelistLogoutHandler.java               | 47 +++++++++++++++
 login/src/main/resources/login-ui.xml         |  8 ++-
 uaa/src/main/resources/login.yml              |  5 +-
 .../identity/uaa/login/LoginMockMvcTests.java | 57 +++++++++++++++++++
 4 files changed, 114 insertions(+), 3 deletions(-)
 create mode 100644 login/src/main/java/org/cloudfoundry/identity/uaa/authentication/WhitelistLogoutHandler.java

diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/authentication/WhitelistLogoutHandler.java b/login/src/main/java/org/cloudfoundry/identity/uaa/authentication/WhitelistLogoutHandler.java
new file mode 100644
index 00000000000..6cac6a9914b
--- /dev/null
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/authentication/WhitelistLogoutHandler.java
@@ -0,0 +1,47 @@
+package org.cloudfoundry.identity.uaa.authentication;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public class WhitelistLogoutHandler extends SimpleUrlLogoutSuccessHandler {
+    private static final Log logger = LogFactory.getLog(WhitelistLogoutHandler.class);
+
+    private List<String> whitelist = null;
+
+    public WhitelistLogoutHandler(List<String> whitelist) {
+        this.whitelist = whitelist;
+    }
+
+    public List<String> getWhitelist() {
+        return whitelist;
+    }
+
+    public void setWhitelist(List<String> whitelist) {
+        this.whitelist = whitelist;
+    }
+
+    @Override
+    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
+        String url =  super.determineTargetUrl(request, response);
+        boolean whitelisted = false;
+        if (whitelist!=null) {
+            for (String s : whitelist) {
+                if (url.equals(s)) {
+                    whitelisted = true;
+                    break;
+                }
+            }
+            if (!whitelisted) {
+                url = getDefaultTargetUrl();
+            }
+        }
+        logger.debug("Logout redirect[whitelisted:"+whitelisted+"; redirect:"+request.getParameter(getTargetUrlParameter())+"] returning:"+url);
+        return url;
+
+    }
+}
diff --git a/login/src/main/resources/login-ui.xml b/login/src/main/resources/login-ui.xml
index 0bc9d3358d7..c35f6ca6e44 100644
--- a/login/src/main/resources/login-ui.xml
+++ b/login/src/main/resources/login-ui.xml
@@ -169,8 +169,12 @@
     <constructor-arg value="/login" />
   </bean>
 
-  <bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
-    <property name="targetUrlParameter" value="redirect" />
+  <bean id="logoutHandler" class="org.cloudfoundry.identity.uaa.authentication.WhitelistLogoutHandler">
+      <constructor-arg value="#{@config['logout']==null ? null :
+                                @config['logout']['redirect']==null ? null :
+                                @config['logout']['redirect']['parameter']==null ? null :
+                                @config['logout']['redirect']['parameter']['whitelist']}"/>
+      <property name="targetUrlParameter" value="redirect" />
     <property name="defaultTargetUrl" value="${logout.redirect.url:/login}" />
     <property name="alwaysUseDefaultTargetUrl" value="${logout.redirect.parameter.disable:true}"/>
   </bean>
diff --git a/uaa/src/main/resources/login.yml b/uaa/src/main/resources/login.yml
index 66d36afebc1..9e9247522ae 100644
--- a/uaa/src/main/resources/login.yml
+++ b/uaa/src/main/resources/login.yml
@@ -41,7 +41,10 @@ links:
 #  redirect:
 #    url: /login
 #    parameter:
-#      disable: true
+#      disable: false
+#      whitelist:
+#        - https://url1.domain1.com/logout-success
+#        - https://url2.domain2.com/logout-success
 
 login:
   # Enable create account and forgot password links on the Login Server (enabled by default)
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
index 8d120ab5e4f..02272f7072e 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
@@ -17,6 +17,7 @@
 import org.cloudfoundry.identity.uaa.TestClassNullifier;
 import org.cloudfoundry.identity.uaa.authentication.Origin;
 import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
+import org.cloudfoundry.identity.uaa.authentication.WhitelistLogoutHandler;
 import org.cloudfoundry.identity.uaa.authentication.login.LoginInfoEndpoint;
 import org.cloudfoundry.identity.uaa.authentication.login.Prompt;
 import org.cloudfoundry.identity.uaa.client.ClientConstants;
@@ -167,6 +168,62 @@ public void testLogOutEnableRedirectParameter() throws Exception {
         }
     }
 
+    @Test
+    public void testLogOutWhitelistedRedirectParameter() throws Exception {
+        WhitelistLogoutHandler logoutSuccessHandler = webApplicationContext.getBean(WhitelistLogoutHandler.class);
+        logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(false);
+        logoutSuccessHandler.setWhitelist(Arrays.asList("https://www.google.com"));
+        try {
+            mockMvc.perform(get("/logout.do").param("redirect", "https://www.google.com"))
+                .andExpect(status().isFound())
+                .andExpect(redirectedUrl("https://www.google.com"));
+        } finally {
+            logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
+        }
+    }
+
+    @Test
+    public void testLogOutNotWhitelistedRedirectParameter() throws Exception {
+        WhitelistLogoutHandler logoutSuccessHandler = webApplicationContext.getBean(WhitelistLogoutHandler.class);
+        logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(false);
+        logoutSuccessHandler.setWhitelist(Arrays.asList("https://www.yahoo.com"));
+        try {
+            mockMvc.perform(get("/logout.do").param("redirect", "https://www.google.com"))
+                .andExpect(status().isFound())
+                .andExpect(redirectedUrl("/login"));
+        } finally {
+            logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
+        }
+    }
+
+    @Test
+    public void testLogOutNullWhitelistedRedirectParameter() throws Exception {
+        WhitelistLogoutHandler logoutSuccessHandler = webApplicationContext.getBean(WhitelistLogoutHandler.class);
+        logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(false);
+        logoutSuccessHandler.setWhitelist(null);
+        try {
+            mockMvc.perform(get("/logout.do").param("redirect", "https://www.google.com"))
+                .andExpect(status().isFound())
+                .andExpect(redirectedUrl("https://www.google.com"));
+        } finally {
+            logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
+        }
+    }
+
+    @Test
+    public void testLogOutEmptyWhitelistedRedirectParameter() throws Exception {
+        WhitelistLogoutHandler logoutSuccessHandler = webApplicationContext.getBean(WhitelistLogoutHandler.class);
+        logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(false);
+        logoutSuccessHandler.setWhitelist(Collections.<String>emptyList());
+        try {
+            mockMvc.perform(get("/logout.do").param("redirect", "https://www.google.com"))
+                .andExpect(status().isFound())
+                .andExpect(redirectedUrl("/login"));
+        } finally {
+            logoutSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
+        }
+    }
+
     @Test
     public void testLogOutChangeUrlValue() throws Exception {
         SimpleUrlLogoutSuccessHandler logoutSuccessHandler = webApplicationContext.getBean(SimpleUrlLogoutSuccessHandler.class);

From ca0b9297762ac320f68886f17d5f054ead06b0a6 Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Fri, 8 May 2015 14:00:17 -0600
Subject: [PATCH 8/9] Properly handle redirects for change_email csrf
 protection Handle avoid redirects if request requests JSON Ensure that
 reset_password has csrf token on it Add CSRF around the invitations, reset
 password and forgot password forms form

---
 .../login/LoginInfoEndpoint.java              |   5 +
 .../uaa/login/ChangePasswordController.java   |   7 +-
 .../uaa/login/UaaChangePasswordService.java   |  10 +-
 .../CsrfAwareEntryPointAndDeniedHandler.java  | 120 +++++++++++++
 login/src/main/resources/login-ui.xml         |  51 ++++--
 .../templates/web/invalid_request.html        |  20 +++
 ...rfAwareEntryPointAndDeniedHandlerTest.java | 112 +++++++++++++
 .../main/webapp/WEB-INF/spring-servlet.xml    |   3 +-
 .../integration/feature/ResetPasswordIT.java  |  14 +-
 .../identity/uaa/login/LoginMockMvcTests.java | 157 +++++++++++++++++-
 .../ResetPasswordControllerMockMvcTests.java  |  24 +++
 11 files changed, 497 insertions(+), 26 deletions(-)
 create mode 100644 login/src/main/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandler.java
 create mode 100644 login/src/main/resources/templates/web/invalid_request.html
 create mode 100644 login/src/test/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandlerTest.java

diff --git a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
index 05903335d01..f9f381114fe 100644
--- a/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
+++ b/common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
@@ -185,6 +185,11 @@ public String loginForHtml(Model model, Principal principal, HttpServletRequest
         return login(model, principal, Arrays.asList("passcode"), false, request);
     }
 
+    @RequestMapping(value = {"/invalid_request" })
+    public String invalidRequest(HttpServletRequest request) {
+        return "invalid_request";
+    }
+
     protected String getZonifiedEntityId() {
         if (UaaUrlUtils.isUrl(entityID)) {
             return UaaUrlUtils.addSubdomainToUrl(entityID);
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/ChangePasswordController.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/ChangePasswordController.java
index 0b4502f4155..0279ef4a0d1 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/ChangePasswordController.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/ChangePasswordController.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -16,6 +16,7 @@
 import static org.springframework.web.bind.annotation.RequestMethod.POST;
 
 import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
@@ -61,7 +62,9 @@ public String changePassword(
         try {
             changePasswordService.changePassword(username, currentPassword, newPassword);
             return "redirect:profile";
-        } catch (RestClientException e) {
+        } catch (BadCredentialsException e) {
+            model.addAttribute("message_code", "unauthorized");
+        } catch (RestClientException e) { //left over from login-server days
             model.addAttribute("message_code", "unauthorized");
         }
         response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaChangePasswordService.java b/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaChangePasswordService.java
index 0d43ee5d559..8775e963b01 100644
--- a/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaChangePasswordService.java
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/login/UaaChangePasswordService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -13,6 +13,8 @@
 package org.cloudfoundry.identity.uaa.login;
 
 import org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.HashMap;
@@ -32,6 +34,10 @@ public void changePassword(String username, String currentPassword, String newPa
         change.setUsername(username);
         change.setCurrentPassword(currentPassword);
         change.setNewPassword(newPassword);
-        passwordResetEndpoints.changePassword(change);
+        ResponseEntity<Map<String,String>> response = passwordResetEndpoints.changePassword(change);
+        if (! response.getStatusCode().is2xxSuccessful()) {
+            //throw an error
+            throw new BadCredentialsException(username);
+        }
     }
 }
diff --git a/login/src/main/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandler.java b/login/src/main/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandler.java
new file mode 100644
index 00000000000..d0c4478ac2d
--- /dev/null
+++ b/login/src/main/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandler.java
@@ -0,0 +1,120 @@
+/*
+ * *****************************************************************************
+ *      Cloud Foundry
+ *      Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
+ *      This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ *      You may not use this product except in compliance with the License.
+ *
+ *      This product includes a number of subcomponents with
+ *      separate copyright notices and license terms. Your use of these
+ *      subcomponents is subject to the terms and conditions of the
+ *      subcomponent's license, as noted in the LICENSE file.
+ * *****************************************************************************
+ */
+
+package org.cloudfoundry.identity.uaa.security;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
+import org.springframework.http.MediaType;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.WebAttributes;
+import org.springframework.security.web.access.AccessDeniedHandler;
+import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
+import org.springframework.security.web.csrf.InvalidCsrfTokenException;
+import org.springframework.security.web.csrf.MissingCsrfTokenException;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+
+public class CsrfAwareEntryPointAndDeniedHandler implements AccessDeniedHandler, AuthenticationEntryPoint {
+
+    private static Log logger = LogFactory.getLog(CsrfAwareEntryPointAndDeniedHandler.class);
+
+    private LoginUrlAuthenticationEntryPoint loginEntryPoint;
+    private LoginUrlAuthenticationEntryPoint csrfEntryPoint;
+
+    public CsrfAwareEntryPointAndDeniedHandler(String redirectCsrf, String redirectNotLoggedIn) {
+        if (redirectCsrf == null || !redirectCsrf.startsWith("/")) {
+            throw new NullPointerException("Invalid CSRF redirect URL, must start with '/'");
+        }
+        if (redirectNotLoggedIn == null || !redirectNotLoggedIn.startsWith("/")) {
+            throw new NullPointerException("Invalid login redirect URL, must start with '/'");
+        }
+        loginEntryPoint = new LoginUrlAuthenticationEntryPoint(redirectNotLoggedIn);
+        csrfEntryPoint = new LoginUrlAuthenticationEntryPoint(redirectCsrf);
+    }
+
+    protected boolean isUserLoggedIn() {
+        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+        return auth!=null && auth.isAuthenticated() && auth.getPrincipal() instanceof UaaPrincipal;
+    }
+
+    protected boolean wantJson(HttpServletRequest request) {
+        String accept = request.getHeader("Accept");
+        boolean json = false;
+        if (StringUtils.hasText(accept)) {
+            for (MediaType mediaType : MediaType.parseMediaTypes(accept)) {
+                if (mediaType.equals(MediaType.APPLICATION_JSON)) {
+                    json = true;
+                    break;
+                }
+            }
+        }
+        return json;
+    }
+
+    protected void internalHandle(HttpServletRequest request,
+                                  HttpServletResponse response,
+                                  Exception exception) throws IOException, ServletException {
+        AuthenticationException authEx = (exception instanceof AuthenticationException) ?
+            (AuthenticationException)exception :
+            new InternalAuthenticationServiceException("Access denied.", exception);
+
+        if (wantJson(request)) {
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+            response.getWriter().append(String.format("{\"error\":\"%s\"}", exception.getMessage()));
+        } else {
+            LoginUrlAuthenticationEntryPoint entryPoint = getLoginUrlAuthenticationEntryPoint(exception);
+            entryPoint.commence(request, response, authEx);
+        }
+    }
+
+    protected LoginUrlAuthenticationEntryPoint getLoginUrlAuthenticationEntryPoint(Exception exception) {
+        if (exception instanceof MissingCsrfTokenException || exception instanceof InvalidCsrfTokenException) {
+            return csrfEntryPoint;
+        } else if (isUserLoggedIn()) {
+            logger.debug("Redirecting to CSRF endpoint based on error.", exception);
+            return csrfEntryPoint;
+        } else {
+            return loginEntryPoint;
+        }
+    }
+
+    @Override
+    public void handle(HttpServletRequest request,
+                       HttpServletResponse response,
+                       AccessDeniedException accessDeniedException) throws IOException,
+        ServletException {
+        request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
+        //if we get any other access denied we end up here
+        internalHandle(request, response, accessDeniedException);
+    }
+
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
+        //if there is insufficient authentication, this will be called
+        internalHandle(request, response, authException);
+    }
+}
diff --git a/login/src/main/resources/login-ui.xml b/login/src/main/resources/login-ui.xml
index c35f6ca6e44..c09cf5a32a9 100644
--- a/login/src/main/resources/login-ui.xml
+++ b/login/src/main/resources/login-ui.xml
@@ -62,17 +62,48 @@
     <bean id="backwardsCompatibleScopeParameter" class="org.cloudfoundry.identity.uaa.oauth.BackwardsCompatibleScopeParsingFilter"/>
 
     <http name="changeEmailSecurity"
+          entry-point-ref="loginEntryPoint"
           use-expressions="false"
           pattern="/change_email**"
           xmlns="http://www.springframework.org/schema/security">
-        <access-denied-handler error-page="/"/>
+        <access-denied-handler ref="loginEntryPoint"/>
         <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
-        <form-login login-page="/login" username-parameter="username" password-parameter="password"
-                    login-processing-url="/login.do" authentication-failure-handler-ref="loginAuthenticationFailureHandler"
-                    authentication-details-source-ref="authenticationDetailsSource"/>
         <csrf disabled="false"/>
     </http>
 
+    <http name="invitationsSecurity"
+          entry-point-ref="loginEntryPoint"
+          use-expressions="false"
+          pattern="/invitations/**"
+          xmlns="http://www.springframework.org/schema/security">
+        <access-denied-handler ref="loginEntryPoint"/>
+        <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
+        <csrf disabled="false"/>
+    </http>
+
+    <http name="resetPasswordSecurity"
+          pattern="/reset_password**"
+          disable-url-rewriting="true"
+          entry-point-ref="loginEntryPoint"
+          use-expressions="false"
+          xmlns="http://www.springframework.org/schema/security">
+        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
+        <csrf disabled="false"/>
+        <access-denied-handler ref="loginEntryPoint"/>
+    </http>
+
+    <http name="forgotPasswordSecurity"
+          pattern="/forgot_password**"
+          disable-url-rewriting="true"
+          entry-point-ref="loginEntryPoint"
+          use-expressions="false"
+          xmlns="http://www.springframework.org/schema/security">
+        <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
+        <csrf disabled="false"/>
+        <access-denied-handler ref="loginEntryPoint"/>
+    </http>
+
+
     <http name="uiSecurity" request-matcher-ref="uiRequestMatcher" use-expressions="false"
           authentication-manager-ref="zoneAwareAuthzAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
       <access-denied-handler error-page="/"/>
@@ -97,13 +128,6 @@
         <property name="defaultFailureUrl" value="/login?error=login_failure" />
     </bean>
 
-    <security:http name="resetPasswordSecurity" pattern="/reset_password.do" disable-url-rewriting="true"
-                   entry-point-ref="loginEntryPoint" use-expressions="false">
-        <security:intercept-url pattern="/reset_password.do" access="IS_AUTHENTICATED_ANONYMOUSLY" />
-        <security:anonymous enabled="true" />
-        <security:csrf disabled="true"/>
-    </security:http>
-
     <security:http name="verifyEmailSecurity" pattern="/verify_email" disable-url-rewriting="true"
                    entry-point-ref="loginEntryPoint" use-expressions="false">
         <security:intercept-url pattern="/verify_email" access="IS_AUTHENTICATED_ANONYMOUSLY" />
@@ -165,8 +189,9 @@
     <bean id="samlFilter" class="org.cloudfoundry.identity.web.NoOpFilter" />
 
 
-  <bean id="loginEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
-    <constructor-arg value="/login" />
+  <bean id="loginEntryPoint" class="org.cloudfoundry.identity.uaa.security.CsrfAwareEntryPointAndDeniedHandler">
+      <constructor-arg name="redirectCsrf" value="/invalid_request" />
+      <constructor-arg name="redirectNotLoggedIn" value="/login" />
   </bean>
 
   <bean id="logoutHandler" class="org.cloudfoundry.identity.uaa.authentication.WhitelistLogoutHandler">
diff --git a/login/src/main/resources/templates/web/invalid_request.html b/login/src/main/resources/templates/web/invalid_request.html
new file mode 100644
index 00000000000..e0f489a8448
--- /dev/null
+++ b/login/src/main/resources/templates/web/invalid_request.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layouts/main">
+<head>
+</head>
+<body>
+<div class="island" layout:fragment="page-content">
+    <div class="island-content">
+        <div class="alert alert-error">
+            <p>Warning</p>
+        </div>
+        <img src="/resources/images/sad_cloud.png" th:src="@{/resources/images/sad_cloud.png}" role="presentation" />
+    </div>
+    <h2>
+        Invalid Request Error<br/>
+        You have attempted to make a request that does not meet our security requirements.<br/>
+        This may indicate that the request was not originated by you.
+    </h2>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/login/src/test/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandlerTest.java b/login/src/test/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandlerTest.java
new file mode 100644
index 00000000000..86bfac0676d
--- /dev/null
+++ b/login/src/test/java/org/cloudfoundry/identity/uaa/security/CsrfAwareEntryPointAndDeniedHandlerTest.java
@@ -0,0 +1,112 @@
+/*
+ * *****************************************************************************
+ *      Cloud Foundry
+ *      Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
+ *      This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ *      You may not use this product except in compliance with the License.
+ *
+ *      This product includes a number of subcomponents with
+ *      separate copyright notices and license terms. Your use of these
+ *      subcomponents is subject to the terms and conditions of the
+ *      subcomponent's license, as noted in the LICENSE file.
+ * *****************************************************************************
+ */
+
+package org.cloudfoundry.identity.uaa.security;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.WebAttributes;
+import org.springframework.security.web.csrf.MissingCsrfTokenException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class CsrfAwareEntryPointAndDeniedHandlerTest {
+
+    protected CsrfAwareEntryPointAndDeniedHandler handler = new CsrfAwareEntryPointAndDeniedHandler("/csrf", "/login");
+    protected MockHttpServletRequest request = new MockHttpServletRequest();
+    protected MockHttpServletResponse response = new MockHttpServletResponse();
+
+    @Before
+    public void setUpCsrfAccessDeniedHandler() throws Exception {
+        response.setCommitted(false);
+    }
+
+    @After
+    public void cleanUpAuth() {
+        SecurityContextHolder.clearContext();
+    }
+
+    @Test
+    public void testHandleWhenCsrfMissing() throws Exception {
+        AccessDeniedException ex = new MissingCsrfTokenException("something");
+        handler.handle(request, response, ex);
+        assertEquals(HttpServletResponse.SC_FOUND, response.getStatus());
+        assertSame(request.getAttribute(WebAttributes.ACCESS_DENIED_403), ex);
+        assertTrue(response.isCommitted());
+        assertEquals("http://localhost/csrf", response.getHeader("Location"));
+        assertEquals(HttpServletResponse.SC_MOVED_TEMPORARILY, response.getStatus());
+    }
+
+    @Test
+    public void testHandleWhenCsrfMissingForJson() throws Exception {
+        request.addHeader("Accept", MediaType.APPLICATION_JSON_VALUE);
+        AccessDeniedException ex = new MissingCsrfTokenException("something");
+        handler.handle(request, response, ex);
+        assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus());
+        assertEquals("{\"error\":\"Expected CSRF token not found. Has your session expired?\"}", response.getContentAsString());
+        assertEquals(null, response.getErrorMessage());
+    }
+
+    @Test
+    public void testHandleWhenNotLoggedIn() throws Exception {
+        AccessDeniedException ex = new AccessDeniedException("something");
+        handler.handle(request, response, ex);
+        assertEquals(HttpServletResponse.SC_FOUND, response.getStatus());
+        assertSame(request.getAttribute(WebAttributes.ACCESS_DENIED_403), ex);
+        assertTrue(response.isCommitted());
+        assertEquals("http://localhost/login", response.getHeader("Location"));
+        assertEquals(HttpServletResponse.SC_MOVED_TEMPORARILY, response.getStatus());
+    }
+
+    @Test
+    public void testHandleWhenNotLoggedInJson() throws Exception {
+        request.addHeader("Accept", MediaType.APPLICATION_JSON_VALUE);
+        AccessDeniedException ex = new AccessDeniedException("something");
+        handler.handle(request, response, ex);
+        assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus());
+        assertEquals("{\"error\":\"something\"}", response.getContentAsString());
+        assertEquals(null, response.getErrorMessage());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullCsrfUrl() {
+        new CsrfAwareEntryPointAndDeniedHandler(null, "/login");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testInvalidCsrfUrl() {
+        new CsrfAwareEntryPointAndDeniedHandler("csrf", "/login");
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullLoginfUrl() {
+        new CsrfAwareEntryPointAndDeniedHandler("/csrf", null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testInvalidLoginUrl() {
+        new CsrfAwareEntryPointAndDeniedHandler("/csrf", "login");
+    }
+
+}
\ No newline at end of file
diff --git a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
index a29e3a554ff..105604fc934 100755
--- a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -46,11 +46,10 @@
     <sec:http name="secFilterOpen07" pattern="/vendor/**" security="none" />
     <!--<sec:http pattern="/login" security="none" />-->
     <sec:http name="secFilterOpen08" pattern="/error" security="none" />
-    <sec:http name="secFilterOpen09" pattern="/forgot_password*" security="none" />
-    <sec:http name="secFilterOpen10" pattern="/reset_password" security="none" />
     <sec:http name="secFilterOpen11" pattern="/email_sent" security="none" />
     <sec:http name="secFilterOpen12" pattern="/create_account*" security="none" />
     <sec:http name="secFilterOpen13" pattern="/accounts/email_sent" security="none" />
+    <sec:http name="secFilterCsrfLandingPage14" pattern="/invalid_request" security="none" />
 
     <bean id="xFrameOptionsFilter" class="org.cloudfoundry.identity.uaa.login.XFrameOptionsFilter" />
     <bean id="oauth2TokenParseFilter" class="java.lang.Class" factory-method="forName">
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ResetPasswordIT.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ResetPasswordIT.java
index 468ad2ee94d..00663a8f1e5 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ResetPasswordIT.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/ResetPasswordIT.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *     Cloud Foundry 
+ *     Cloud Foundry
  *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
  *
  *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -12,6 +12,8 @@
  *******************************************************************************/
 package org.cloudfoundry.identity.uaa.integration.feature;
 
+import java.io.File;
+import java.io.IOException;
 import java.security.SecureRandom;
 import java.util.Iterator;
 
@@ -20,6 +22,7 @@
 import static org.junit.Assert.assertThat;
 import com.dumbster.smtp.SimpleSmtpServer;
 import com.dumbster.smtp.SmtpMessage;
+import org.apache.commons.io.FileUtils;
 import org.cloudfoundry.identity.uaa.login.test.LoginServerClassRunner;
 import org.cloudfoundry.identity.uaa.login.test.UnlessProfileActive;
 import org.hamcrest.Matchers;
@@ -30,6 +33,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.openqa.selenium.By;
+import org.openqa.selenium.OutputType;
+import org.openqa.selenium.TakesScreenshot;
 import org.openqa.selenium.WebDriver;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -167,4 +172,11 @@ public void resettingAPasswordForANonExistentUser() throws Exception {
 
         assertEquals(receivedEmailSize, simpleSmtpServer.getReceivedEmailSize());
     }
+
+    public void takeScreenShot() throws IOException {
+        File scrFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
+        File destFile = new File("testscreenshot-" + System.currentTimeMillis() + ".png");
+        FileUtils.copyFile(scrFile, destFile);
+        System.out.println("Screenshot in : " + destFile.getAbsolutePath());
+    }
 }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
index 02272f7072e..d0d0be9dad1 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/LoginMockMvcTests.java
@@ -36,7 +36,6 @@
 import org.cloudfoundry.identity.uaa.zone.IdentityZone;
 import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
 import org.junit.AfterClass;
-import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.mock.env.MockEnvironment;
@@ -64,7 +63,6 @@
 import org.springframework.web.context.support.XmlWebApplicationContext;
 
 import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpSession;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -72,7 +70,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import static org.hamcrest.Matchers.any;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasEntry;
 import static org.hamcrest.Matchers.hasKey;
@@ -85,11 +82,11 @@
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.securityContext;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
@@ -112,6 +109,7 @@ public class LoginMockMvcTests extends TestClassNullifier {
     public static void setUpContext() throws Exception {
         SecurityContextHolder.clearContext();
         webApplicationContext = new XmlWebApplicationContext();
+        mockEnvironment.setProperty("login.invitationsEnabled", "true");
         webApplicationContext.setEnvironment(mockEnvironment);
         new YamlServletProfileInitializerContextInitializer().initializeContext(webApplicationContext, "login.yml,uaa.yml");
         webApplicationContext.setConfigLocation("file:./src/main/webapp/WEB-INF/spring-servlet.xml");
@@ -597,7 +595,8 @@ public void testChangeEmailSubmitWithMissingCsrf() throws Exception {
             .param("newEmail", "test@test.org")
             .param("client_id", "");
         mockMvc.perform(changeEmail)
-            .andExpect(status().is4xxClientError());
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
     }
 
     @Test
@@ -621,7 +620,8 @@ public void testChangeEmailSubmitWithInvalidCsrf() throws Exception {
             .param("client_id", "")
             .param("_csrf", "invalid csrf token");
         mockMvc.perform(changeEmail)
-            .andExpect(status().is4xxClientError());
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
     }
 
     @Test
@@ -669,5 +669,150 @@ public void testChangeEmailSubmitWithCorrectCsrf() throws Exception {
 
     }
 
+    @Test
+    public void testChangeEmailDoNotLoggedIn() throws Exception {
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
+
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .with(csrf());
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/login"));
+
+        changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .with(csrf().useInvalidToken());
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+
+        changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .with(csrf().useInvalidToken())
+            .with(securityContext(marissaContext));
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+    }
+
+    @Test
+    public void testChangeEmailNoCsrfReturns403AndInvalidRequest() throws Exception {
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
+
+        MockHttpServletRequestBuilder get = get("/change_email")
+            .accept(TEXT_HTML)
+            .with(securityContext(marissaContext));
+
+        mockMvc.perform(get)
+            .andExpect(status().isOk())
+            .andExpect(content().string(containsString("_csrf")))
+            .andReturn();
+
+        MockHttpServletRequestBuilder changeEmail = post("/change_email.do")
+            .accept(TEXT_HTML)
+            .with(securityContext(marissaContext))
+            .param("newEmail", "test@test.org")
+            .param("client_id", "");
+        mockMvc.perform(changeEmail)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+    }
+
+    @Test
+    public void testCsrfForInvitationPost() throws Exception {
+        RandomValueStringGenerator generator = new RandomValueStringGenerator();
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
+
+        //logged in with valid CSRF
+        MockHttpServletRequestBuilder post = post("/invitations/new.do")
+            .with(securityContext(marissaContext))
+            .with(csrf())
+            .param("email", generator.generate()+"@example.com");
+
+        mockMvc.perform(post)
+            .andDo(print())
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("sent"));
+
+        //logged in, invalid CSRF
+        post = post("/invitations/new.do")
+            .with(securityContext(marissaContext))
+            .with(csrf().useInvalidToken())
+            .param("email", generator.generate()+"@example.com");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+
+        //not logged in, no CSRF
+        post = post("/invitations/new.do")
+            .param("email", generator.generate()+"@example.com");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+
+        //not logged in, valid CSRF(can't happen)
+        post = post("/invitations/new.do")
+            .with(csrf())
+            .param("email", generator.generate()+"@example.com");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/login"));
+
+    }
+
+    @Test
+    public void testCsrfForInvitationAcceptPost() throws Exception {
+        SecurityContext marissaContext = MockMvcUtils.utils().getMarissaSecurityContext(webApplicationContext);
+
+        //logged in with valid CSRF
+        MockHttpServletRequestBuilder post = post("/invitations/accept.do")
+            .with(securityContext(marissaContext))
+            .with(csrf())
+            .param("client_id", "random")
+            .param("password", "password")
+            .param("password_confirmation", "yield_unprocessable_entity");
+
+        mockMvc.perform(post)
+            .andDo(print())
+            .andExpect(status().isUnprocessableEntity());
+
+        //logged in, invalid CSRF
+        post = post("/invitations/accept.do")
+            .with(securityContext(marissaContext))
+            .with(csrf().useInvalidToken())
+            .param("client_id", "random")
+            .param("password", "password")
+            .param("password_confirmation", "yield_unprocessable_entity");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+
+        //not logged in, no CSRF
+        post = post("/invitations/accept.do")
+            .param("client_id", "random")
+            .param("password", "password")
+            .param("password_confirmation", "yield_unprocessable_entity");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+
+        //not logged in, valid CSRF(can't happen)
+        post = post("/invitations/accept.do")
+            .with(csrf())
+            .param("client_id", "random")
+            .param("password", "password")
+            .param("password_confirmation", "yield_unprocessable_entity");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/login"));
+
+    }
 
 }
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java
index 3a7e7f2097a..485dd6d80b3 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/login/ResetPasswordControllerMockMvcTests.java
@@ -46,7 +46,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
@@ -92,6 +94,7 @@ public void testResettingAPasswordUsingUsernameToEnsureNoModification() throws E
         ExpiringCode code = codeStore.generateCode(JsonUtils.writeValueAsString(change), new Timestamp(System.currentTimeMillis()+ PASSWORD_RESET_LIFETIME));
 
         MockHttpServletRequestBuilder post = post("/reset_password.do")
+            .with(csrf())
             .param("code", code.getCode())
             .param("email", users.get(0).getPrimaryEmail())
             .param("password", "newpassword")
@@ -131,6 +134,7 @@ public void testResettingAPasswordFailsWhenUsernameChanged() throws Exception {
         user = userProvisioning.update(user.getId(), user);
         try {
             MockHttpServletRequestBuilder post = post("/reset_password.do")
+                .with(csrf())
                 .param("code", code.getCode())
                 .param("email", user.getPrimaryEmail())
                 .param("password", "newpassword")
@@ -144,6 +148,24 @@ public void testResettingAPasswordFailsWhenUsernameChanged() throws Exception {
         }
     }
 
+    @Test
+    public void testResettingAPasswordNoCsrfParameter() throws Exception {
+        List<ScimUser> users = webApplicationContext.getBean(ScimUserProvisioning.class).query("username eq \"marissa\"");
+        assertNotNull(users);
+        assertEquals(1, users.size());
+        ExpiringCode code = codeStore.generateCode(users.get(0).getId(), new Timestamp(System.currentTimeMillis() + PASSWORD_RESET_LIFETIME));
+
+        MockHttpServletRequestBuilder post = post("/reset_password.do")
+            .param("code", code.getCode())
+            .param("email", users.get(0).getPrimaryEmail())
+            .param("password", "newpassword")
+            .param("password_confirmation", "newpassword");
+
+        mockMvc.perform(post)
+            .andExpect(status().isFound())
+            .andExpect(redirectedUrl("http://localhost/invalid_request"));
+    }
+
     @Test
     public void testResettingAPasswordUsingTimestampForUserModification() throws Exception {
         List<ScimUser> users = webApplicationContext.getBean(ScimUserProvisioning.class).query("username eq \"marissa\"");
@@ -152,6 +174,7 @@ public void testResettingAPasswordUsingTimestampForUserModification() throws Exc
         ExpiringCode code = codeStore.generateCode(users.get(0).getId(), new Timestamp(System.currentTimeMillis()+ PASSWORD_RESET_LIFETIME));
 
         MockHttpServletRequestBuilder post = post("/reset_password.do")
+            .with(csrf())
             .param("code", code.getCode())
             .param("email", users.get(0).getPrimaryEmail())
             .param("password", "newpassword")
@@ -182,6 +205,7 @@ public void testResettingAPasswordUsingTimestampUserModified() throws Exception
         ExpiringCode code = codeStore.generateCode(user.getId(), new Timestamp(System.currentTimeMillis() + PASSWORD_RESET_LIFETIME));
 
         MockHttpServletRequestBuilder post = post("/reset_password.do")
+            .with(csrf())
             .param("code", code.getCode())
             .param("email", user.getPrimaryEmail())
             .param("password", "newpassword")

From d78c6be93ff5d5c778501bb6caf0f5b7cd761f0a Mon Sep 17 00:00:00 2001
From: Filip Hanik <fhanik@pivotal.io>
Date: Fri, 8 May 2015 20:50:41 -0600
Subject: [PATCH 9/9] Bump release version to 2.3.0

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 65362284ef9..7ad95fa51f7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +1 @@
-version=2.3.0-SNAPSHOT
+version=2.3.0