Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/1.3.1'

Conflicts:
	common/pom.xml
	common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
	gem/lib/uaa/version.rb
	pom.xml
	samples/api/pom.xml
	samples/app/pom.xml
	samples/login/pom.xml
	samples/pom.xml
	uaa/pom.xml

Change-Id: I48acdd2693e7a1b34ccf250c1fe1aa2c85634765
  • Loading branch information...
commit 84867654e58da9eb15dea127c55defa8f5a14835 2 parents 01631cc + d4be87f
Joel D'sa joeldsa authored
Showing with 5,122 additions and 3,455 deletions.
  1. +14 −14 README.md
  2. +6 −9 common/pom.xml
  3. +1 −0  common/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEvent.java
  4. +10 −2 common/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java
  5. +12 −56 common/src/main/java/org/cloudfoundry/identity/uaa/audit/JdbcAuditService.java
  6. +16 −66 common/src/main/java/org/cloudfoundry/identity/uaa/audit/JdbcFailedLoginCountingAuditService.java
  7. +45 −26 common/src/main/java/org/cloudfoundry/identity/uaa/audit/LoggingAuditService.java
  8. +14 −15 common/src/main/java/org/cloudfoundry/identity/uaa/audit/UaaAuditService.java
  9. +103 −0 common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java
  10. +44 −0 common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AuditListener.java
  11. +3 −3 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
  12. +34 −1 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/UaaAuthenticationDetails.java
  13. +11 −1 .../main/java/org/cloudfoundry/identity/uaa/{ → authentication}/event/AbstractUaaAuthenticationEvent.java
  14. +35 −0 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaPrincipalEvent.java
  15. +50 −0 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/BadCredentialsListener.java
  16. +39 −0 ...n/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/PrincipalAuthenticationFailureEvent.java
  17. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/PrincipalNotFoundEvent.java
  18. +10 −5 .../main/java/org/cloudfoundry/identity/uaa/{ → authentication}/event/UserAuthenticationFailureEvent.java
  19. +9 −5 .../main/java/org/cloudfoundry/identity/uaa/{ → authentication}/event/UserAuthenticationSuccessEvent.java
  20. +22 −5 common/src/main/java/org/cloudfoundry/identity/uaa/{ → authentication}/event/UserNotFoundEvent.java
  21. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
  22. +24 −11 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java
  23. +11 −17 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java
  24. +11 −8 ...dry/identity/uaa/{event/AbstractUaaEvent.java → authentication/manager/NewUserAuthenticatedEvent.java}
  25. +170 −0 common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientAuthenticationFilter.java
  26. +50 −0 common/src/main/java/org/cloudfoundry/identity/uaa/client/OAuth2AccessTokenSource.java
  27. +24 −0 common/src/main/java/org/cloudfoundry/identity/uaa/client/PreAuthenticatedPrincipalSource.java
  28. +29 −6 common/src/main/java/org/cloudfoundry/identity/uaa/{social → client}/SocialClientUserDetails.java
  29. +8 −6 common/src/main/java/org/cloudfoundry/identity/uaa/{social → client}/SocialClientUserDetailsSource.java
  30. +12 −0 common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlMapFactoryBean.java
  31. +1 −0  common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlProcessor.java
  32. +9 −0 common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlPropertiesFactoryBean.java
  33. +0 −59 common/src/main/java/org/cloudfoundry/identity/uaa/event/listener/AuditListener.java
  34. +1 −12 common/src/main/java/org/cloudfoundry/identity/uaa/{scim → message}/PasswordChangeRequest.java
  35. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/{rest → message}/SimpleMessage.java
  36. +47 −24 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminBootstrap.java
  37. +25 −5 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpoints.java
  38. +5 −42 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/TokenAdminEndpoints.java
  39. +43 −12 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/UaaUserApprovalHandler.java
  40. +42 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/AbstractClientAdminEvent.java
  41. +99 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/ClientAdminEventPublisher.java
  42. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/ClientCreateEvent.java
  43. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/ClientDeleteEvent.java
  44. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/ClientUpdateEvent.java
  45. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/SecretChangeEvent.java
  46. +52 −0 common/src/main/java/org/cloudfoundry/identity/uaa/oauth/event/SecretFailureEvent.java
  47. +131 −0 common/src/main/java/org/cloudfoundry/identity/uaa/password/PasswordChangeEndpoint.java
  48. +2 −0  common/src/main/java/org/cloudfoundry/identity/uaa/password/PasswordCheckEndpoint.java
  49. +3 −0  common/src/main/java/org/cloudfoundry/identity/uaa/password/ZxcvbnPasswordScoreCalculator.java
  50. +6 −3 common/src/main/java/org/cloudfoundry/identity/uaa/{scim → password}/ZxcvbnPasswordValidator.java
  51. +22 −15 ...a → common/src/main/java/org/cloudfoundry/identity/uaa/password/event/AbstractPasswordChangeEvent.java
  52. +38 −0 common/src/main/java/org/cloudfoundry/identity/uaa/password/event/PasswordChangeEvent.java
  53. +103 −0 common/src/main/java/org/cloudfoundry/identity/uaa/password/event/PasswordChangeEventPublisher.java
  54. +49 −0 common/src/main/java/org/cloudfoundry/identity/uaa/password/event/PasswordFailureEvent.java
  55. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimCore.java
  56. +1 −2  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → }/ScimGroup.java
  57. +3 −1 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → }/ScimGroupMember.java
  58. +16 −6 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → }/ScimGroupMembershipManager.java
  59. +4 −4 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → }/ScimGroupProvisioning.java
  60. +2 −2 common/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimMeta.java
  61. +15 −15 common/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUser.java
  62. +4 −0 common/src/main/java/org/cloudfoundry/identity/uaa/scim/ScimUserProvisioning.java
  63. +15 −10 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → bootstrap}/ScimGroupBootstrap.java
  64. +20 −4 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → bootstrap}/ScimUserBootstrap.java
  65. +1 −1  ...n/src/main/java/org/cloudfoundry/identity/uaa/{config → scim/endpoints}/HandlerAdapterFactoryBean.java
  66. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/{password → scim/endpoints}/PasswordScore.java
  67. +1 −1  ...n/src/main/java/org/cloudfoundry/identity/uaa/{password → scim/endpoints}/PasswordScoreCalculator.java
  68. +62 −40 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → endpoints}/ScimGroupEndpoints.java
  69. +36 −100 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/ScimUserEndpoints.java
  70. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/SearchResults.java
  71. +12 −7 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/SearchResultsFactory.java
  72. +2 −2 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/UserIdConversionEndpoints.java
  73. +116 −0 common/src/main/java/org/cloudfoundry/identity/uaa/scim/endpoints/UserIdInjector.java
  74. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/InvalidPasswordException.java
  75. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/InvalidScimResourceException.java
  76. +1 −2  ...rc/main/java/org/cloudfoundry/identity/uaa/scim/{groups → exception}/MemberAlreadyExistsException.java
  77. +1 −2  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → exception}/MemberNotFoundException.java
  78. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/ScimException.java
  79. +1 −1  ...rc/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/ScimResourceAlreadyExistsException.java
  80. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/ScimResourceConflictException.java
  81. +32 −0 common/src/main/java/org/cloudfoundry/identity/uaa/scim/exception/ScimResourceConstraintFailedException.java
  82. +2 −2 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → exception}/ScimResourceNotFoundException.java
  83. +5 −5 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/JdbcPagingList.java
  84. +79 −30 ...n/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → jdbc}/JdbcScimGroupMembershipManager.java
  85. +17 −18 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{groups → jdbc}/JdbcScimGroupProvisioning.java
  86. +28 −13 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/JdbcScimUserProvisioning.java
  87. +3 −1 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/ScimSearchQueryConverter.java
  88. +3 −1 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/SearchQueryConverter.java
  89. +10 −4 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → remote}/RemoteScimUserProvisioning.java
  90. +66 −0 common/src/main/java/org/cloudfoundry/identity/uaa/scim/security/GroupVoter.java
  91. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → util}/AttributeNameMapper.java
  92. +3 −2 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → util}/SimpleAttributeNameMapper.java
  93. +6 −6 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → util}/json/JsonDateDeserializer.java
  94. +5 −5 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → util}/json/JsonDateSerializer.java
  95. +9 −8 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → validate}/DefaultPasswordValidator.java
  96. +4 −1 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → validate}/NullPasswordValidator.java
  97. +4 −1 common/src/main/java/org/cloudfoundry/identity/uaa/scim/{ → validate}/PasswordValidator.java
  98. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/security/SecurityContextAccessor.java
  99. +214 −0 common/src/main/java/org/cloudfoundry/identity/uaa/security/web/SecurityFilterChainPostProcessor.java
  100. +44 −5 common/src/main/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcher.java
  101. +0 −94 common/src/main/java/org/cloudfoundry/identity/uaa/social/SocialClientAuthenticationFilter.java
  102. +0 −1  common/src/main/java/org/cloudfoundry/identity/uaa/test/ParentContextLoader.java
  103. +40 −29 common/src/main/java/org/cloudfoundry/identity/uaa/{integration → test}/TestAccountSetup.java
  104. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/{integration → test}/TestProfileEnvironment.java
  105. +0 −1  common/src/main/java/org/cloudfoundry/identity/uaa/test/TestUtils.java
  106. +3 −5 common/src/main/java/org/cloudfoundry/identity/uaa/{integration → test}/UaaTestAccounts.java
  107. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/{integration → test}/UrlHelper.java
  108. +10 −3 common/src/main/java/org/cloudfoundry/identity/uaa/user/JdbcUaaUserDatabase.java
  109. +0 −2  common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaUser.java
  110. +1 −1  common/src/main/java/org/cloudfoundry/identity/uaa/user/UaaUserEditor.java
  111. +0 −204 common/src/main/java/org/cloudfoundry/identity/uaa/varz/MBeanMap.java
  112. +0 −429 common/src/main/java/org/cloudfoundry/identity/uaa/varz/VarzEndpoint.java
  113. +14 −10 common/src/main/java/org/cloudfoundry/identity/uaa/{varz → web}/HealthzEndpoint.java
  114. +6 −2 common/src/main/resources/org/cloudfoundry/identity/uaa/schema-drop-hsqldb.sql
  115. +6 −2 common/src/main/resources/org/cloudfoundry/identity/uaa/schema-drop-postgresql.sql
  116. +38 −8 common/src/main/resources/org/cloudfoundry/identity/uaa/schema-hsqldb.sql
  117. +38 −8 common/src/main/resources/org/cloudfoundry/identity/uaa/schema-postgresql.sql
  118. +1 −0  common/src/main/sql/hsqldb.properties
  119. +1 −0  common/src/main/sql/hsqldb.vpp
  120. +1 −0  common/src/main/sql/postgresql.properties
  121. +1 −0  common/src/main/sql/postgresql.vpp
  122. +7 −1 common/src/main/sql/schema-drop.sql.vpp
  123. +53 −5 common/src/main/sql/schema.sql.vpp
  124. +18 −19 common/src/test/java/org/cloudfoundry/identity/uaa/audit/JdbcAuditServiceTests.java
  125. +26 −32 common/src/test/java/org/cloudfoundry/identity/uaa/audit/JdbcFailedLoginCountingAuditServiceTests.java
  126. +10 −7 common/src/test/java/org/cloudfoundry/identity/uaa/{event/listener → audit/event}/AuditListenerTests.java
  127. +0 −225 common/src/test/java/org/cloudfoundry/identity/uaa/authentication/RubyUserTokenTests.java
  128. +3 −1 common/src/test/java/org/cloudfoundry/identity/uaa/authentication/UaaAuthenticationTestFactory.java
  129. +3 −3 common/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManagerTests.java
  130. +0 −4 common/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManagerTests.java
  131. +7 −4 ...c/test/java/org/cloudfoundry/identity/uaa/{social → client}/OAuth2ClientAuthenticationFilterTests.java
  132. +7 −4 ...rc/test/java/org/cloudfoundry/identity/uaa/{social → client}/OAuthClientAuthenticationFilterTests.java
  133. +2 −2 common/src/test/java/org/cloudfoundry/identity/uaa/{social → client}/SourceTests.java
  134. +1 −1  common/src/test/java/org/cloudfoundry/identity/uaa/error/ConvertingExceptionViewTests.java
  135. +37 −20 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminBootstrapTests.java
  136. +52 −6 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/ClientAdminEndpointsTests.java
  137. +11 −25 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/TokenAdminEndpointsTests.java
  138. +78 −0 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/UaaUserApprovalHandlerTests.java
  139. +109 −0 common/src/test/java/org/cloudfoundry/identity/uaa/oauth/event/ClientAdminEventPublisherTests.java
  140. +144 −0 common/src/test/java/org/cloudfoundry/identity/uaa/password/PasswordChangeEndpointTests.java
  141. +1 −0  common/src/test/java/org/cloudfoundry/identity/uaa/password/PasswordCheckEndpointTests.java
  142. +89 −0 common/src/test/java/org/cloudfoundry/identity/uaa/password/event/PasswordChangeEventPublisherTests.java
  143. +1 −0  common/src/test/java/org/cloudfoundry/identity/uaa/rest/MessageTests.java
  144. +7 −2 common/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimCoreTests.java
  145. +1 −0  common/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimExceptionStatusCodeMatcher.java
  146. +7 −2 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{groups → }/ScimGroupMemberTests.java
  147. +9 −8 common/src/test/java/org/cloudfoundry/identity/uaa/scim/ScimUserTests.java
  148. +13 −11 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{groups → bootstrap}/ScimGroupBootstrapTests.java
  149. +14 −10 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → bootstrap}/ScimUserBootstrapTests.java
  150. +2 −1  .../test/java/org/cloudfoundry/identity/uaa/{config → scim/endpoints}/HandlerAdapterFactoryBeanTests.java
  151. +433 −0 common/src/test/java/org/cloudfoundry/identity/uaa/scim/endpoints/ScimGroupEndpointsTests.java
  152. +52 −100 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/ScimUserEndpointsTests.java
  153. +4 −2 ...on/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → endpoints}/UserIdConversionEndpointsTests.java
  154. +0 −241 common/src/test/java/org/cloudfoundry/identity/uaa/scim/groups/ScimGroupEndpointsTests.java
  155. +12 −12 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/JdbcPagingListTests.java
  156. +47 −24 .../test/java/org/cloudfoundry/identity/uaa/scim/{groups → jdbc}/JdbcScimGroupMembershipManagerTests.java
  157. +44 −10 ...n/src/test/java/org/cloudfoundry/identity/uaa/scim/{groups → jdbc}/JdbcScimGroupProvisioningTests.java
  158. +47 −11 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/JdbcScimUserProvisioningTests.java
  159. +7 −5 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → jdbc}/ScimSearchQueryConverterTests.java
  160. +8 −5 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → remote}/RemoteScimUserProvisioningTests.java
  161. +4 −1 common/src/test/java/org/cloudfoundry/identity/uaa/scim/{ → validate}/DefaultPasswordValidatorTests.java
  162. +15 −0 common/src/test/java/org/cloudfoundry/identity/uaa/security/web/UaaRequestMatcherTests.java
  163. +24 −9 common/src/test/java/org/cloudfoundry/identity/uaa/user/JdbcUaaUserDatabaseTests.java
  164. +3 −3 common/src/test/java/org/cloudfoundry/identity/uaa/user/UaaUserEditorTests.java
  165. +0 −57 common/src/test/java/org/cloudfoundry/identity/uaa/varz/MBeanMapTests.java
  166. +0 −103 common/src/test/java/org/cloudfoundry/identity/uaa/varz/VarzEndpointTests.java
  167. +1 −1  common/src/test/java/org/cloudfoundry/identity/uaa/{varz → web}/HealthzEndpointTests.java
  168. +212 −13 docs/UAA-APIs.rst
  169. +9 −35 gatling/README.md
  170. +3 −3 gatling/pom.xml
  171. +5 −5 gatling/project/Build.scala
  172. +1 −1  gatling/src/main/ab/login_marissa.txt
  173. +9 −0 gatling/src/main/resources/application.conf
  174. +2 −2 gatling/src/main/resources/logback.xml
  175. +4 −5 gatling/src/main/scala/AccountLockoutSimulation.scala
  176. +0 −109 gatling/src/main/scala/AcmBaseDataCreationSimulation.scala
  177. +0 −40 gatling/src/main/scala/AcmPermissionSetCreationSimulation.scala
  178. +0 −82 gatling/src/main/scala/AcmSmokeSimulation.scala
  179. +22 −0 gatling/src/main/scala/AuthCodeFlowSimulation.scala
  180. +44 −6 gatling/src/main/scala/ScimWorkoutSimulation.scala
  181. +27 −3 gatling/src/main/scala/UaaBaseDataCreationSimulation.scala
  182. +50 −17 gatling/src/main/scala/UaaSmokeSimulation.scala
  183. +26 −8 gatling/src/main/scala/uaa/Config.scala
  184. +63 −59 gatling/src/main/scala/uaa/OAuthComponents.scala
  185. +133 −20 gatling/src/main/scala/uaa/ScimApi.scala
  186. +96 −0 gatling/src/main/scala/uaa/ScimFeeders.scala
  187. +0 −23 gatling/src/main/scala/uaa/UniqueUsernamePasswordFeeder.scala
  188. +2 −0  gatling/src/main/scala/uaa/UsernamePasswordFeeder.scala
  189. +9 −4 gatling/src/main/scala/uaa/uaaApis.scala
  190. +9 −18 gatling/src/test/scala/Engine.scala
  191. +11 −22 gatling/src/test/scala/IDEPathHelper.scala
  192. +5 −19 gatling/src/test/scala/Recorder.scala
  193. +27 −22 gem/README.md
  194. +8 −0 gem/bin/uaas
  195. +2 −2 gem/cf-uaa-client.gemspec
  196. +0 −1  gem/lib/cli/base.rb
  197. +5 −2 gem/lib/cli/info.rb
  198. +26 −9 gem/lib/cli/stub_server.rb
  199. +9 −7 gem/lib/cli/token.rb
  200. +1 −3 gem/lib/uaa/user_account.rb
  201. +2 −1  gem/lib/uaa/version.rb
  202. +5 −0 gem/spec/cli_spec.rb
  203. +54 −1 gem/spec/stub_uaa.rb
  204. +51 −26 pom.xml
  205. +1 −1  samples/api/pom.xml
  206. +2 −2 samples/api/src/test/java/org/cloudfoundry/identity/api/web/AppsIntegrationTests.java
  207. +2 −2 samples/api/src/test/java/org/cloudfoundry/identity/api/web/CloudfoundryApiIntegrationTests.java
  208. +1 −1  samples/api/src/test/java/org/cloudfoundry/identity/api/web/ServerRunning.java
  209. +1 −1  samples/app/pom.xml
  210. +1 −1  samples/app/src/main/java/org/cloudfoundry/identity/app/web/TreeController.java
  211. +1 −0  samples/app/src/main/resources/application-devlogin-devuaa.properties
  212. +1 −0  samples/app/src/main/resources/application-devuaa.properties
  213. +2 −1  samples/app/src/main/resources/application-local-prod.properties
  214. +1 −0  samples/app/src/main/resources/application-local-staging.properties
  215. +1 −0  samples/app/src/main/resources/application-local-vcap.properties
  216. +1 −0  samples/app/src/main/resources/application-local.properties
  217. +1 −0  samples/app/src/main/resources/application-login-prod.properties
  218. +1 −0  samples/app/src/main/resources/application-login-staging.properties
  219. +1 −0  samples/app/src/main/resources/application-prod.properties
  220. +1 −0  samples/app/src/main/resources/application-ruby-local.properties
  221. +1 −0  samples/app/src/main/resources/application-staging.properties
  222. +1 −0  samples/app/src/main/resources/application-test-prod.properties
  223. +1 −0  samples/app/src/main/resources/application-test-staging.properties
  224. +1 −0  samples/app/src/main/resources/application.properties
  225. +42 −14 samples/app/src/main/webapp/WEB-INF/spring-servlet.xml
  226. +1 −1  samples/app/src/main/webapp/home.jsp
  227. +3 −16 samples/app/src/test/java/org/cloudfoundry/identity/app/integration/AuthenticationIntegrationTests.java
  228. +3 −3 samples/app/src/test/java/org/cloudfoundry/identity/app/integration/ServerRunning.java
  229. +0 −14 samples/login/.springBeans
  230. 0  samples/{ruby-login-server → login}/Gemfile
  231. 0  samples/{ruby-login-server → login}/Gemfile.lock
  232. 0  samples/{ruby-login-server → login}/README.md
  233. 0  samples/{ruby-login-server → login}/config.ru
  234. 0  samples/{ruby-login-server → login}/login.rb
  235. 0  samples/{ruby-login-server → login}/openid_login.rb
  236. +0 −311 samples/login/pom.xml
  237. 0  samples/{ruby-login-server → login}/public/css/openid-shadow.css
  238. 0  samples/{ruby-login-server → login}/public/css/openid.css
  239. 0  samples/{ruby-login-server → login}/public/images.large/aol.gif
  240. 0  samples/{ruby-login-server → login}/public/images.large/facebook.gif
  241. 0  samples/{ruby-login-server → login}/public/images.large/google.gif
  242. 0  samples/{ruby-login-server → login}/public/images.large/mailru.gif
  243. 0  samples/{ruby-login-server → login}/public/images.large/myopenid.gif
  244. 0  samples/{ruby-login-server → login}/public/images.large/openid.gif
  245. 0  samples/{ruby-login-server → login}/public/images.large/rambler.gif
  246. 0  samples/{ruby-login-server → login}/public/images.large/verisign.gif
  247. 0  samples/{ruby-login-server → login}/public/images.large/vkontakte.gif
  248. 0  samples/{ruby-login-server → login}/public/images.large/yahoo.gif
  249. 0  samples/{ruby-login-server → login}/public/images.large/yandex.gif
  250. 0  samples/{ruby-login-server → login}/public/images.small/aol.ico
  251. 0  samples/{ruby-login-server → login}/public/images.small/aol.ico.gif
  252. 0  samples/{ruby-login-server → login}/public/images.small/aol.ico.png
  253. 0  samples/{ruby-login-server → login}/public/images.small/blogger.ico
  254. 0  samples/{ruby-login-server → login}/public/images.small/blogger.ico.gif
  255. 0  samples/{ruby-login-server → login}/public/images.small/blogger.ico.png
  256. 0  samples/{ruby-login-server → login}/public/images.small/claimid.ico
  257. 0  samples/{ruby-login-server → login}/public/images.small/claimid.ico.gif
  258. 0  samples/{ruby-login-server → login}/public/images.small/claimid.ico.png
  259. 0  samples/{ruby-login-server → login}/public/images.small/clickpass.ico
  260. 0  samples/{ruby-login-server → login}/public/images.small/clickpass.ico.gif
  261. 0  samples/{ruby-login-server → login}/public/images.small/clickpass.ico.png
  262. 0  samples/{ruby-login-server → login}/public/images.small/facebook.ico
  263. 0  samples/{ruby-login-server → login}/public/images.small/facebook.ico.gif
  264. 0  samples/{ruby-login-server → login}/public/images.small/facebook.ico.png
  265. 0  samples/{ruby-login-server → login}/public/images.small/flickr.ico
  266. 0  samples/{ruby-login-server → login}/public/images.small/flickr.ico.gif
  267. 0  samples/{ruby-login-server → login}/public/images.small/flickr.ico.png
  268. 0  samples/{ruby-login-server → login}/public/images.small/google.ico
  269. 0  samples/{ruby-login-server → login}/public/images.small/google.ico.gif
  270. 0  samples/{ruby-login-server → login}/public/images.small/google.ico.png
  271. 0  samples/{ruby-login-server → login}/public/images.small/google_profile.ico
  272. 0  samples/{ruby-login-server → login}/public/images.small/google_profile.ico.gif
  273. 0  samples/{ruby-login-server → login}/public/images.small/google_profile.ico.png
  274. 0  samples/{ruby-login-server → login}/public/images.small/launchpad.ico
  275. 0  samples/{ruby-login-server → login}/public/images.small/launchpad.ico.gif
  276. 0  samples/{ruby-login-server → login}/public/images.small/launchpad.ico.png
  277. 0  samples/{ruby-login-server → login}/public/images.small/linkedin.ico
  278. 0  samples/{ruby-login-server → login}/public/images.small/linkedin.ico.gif
  279. 0  samples/{ruby-login-server → login}/public/images.small/linkedin.ico.png
  280. 0  samples/{ruby-login-server → login}/public/images.small/livejournal.ico
  281. 0  samples/{ruby-login-server → login}/public/images.small/livejournal.ico.gif
  282. 0  samples/{ruby-login-server → login}/public/images.small/livejournal.ico.png
  283. 0  samples/{ruby-login-server → login}/public/images.small/mailru.ico
  284. 0  samples/{ruby-login-server → login}/public/images.small/mailru.ico.gif
  285. 0  samples/{ruby-login-server → login}/public/images.small/mailru.ico.png
  286. 0  samples/{ruby-login-server → login}/public/images.small/myopenid.ico
  287. 0  samples/{ruby-login-server → login}/public/images.small/myopenid.ico.gif
  288. 0  samples/{ruby-login-server → login}/public/images.small/myopenid.ico.png
  289. 0  samples/{ruby-login-server → login}/public/images.small/openid.ico
  290. 0  samples/{ruby-login-server → login}/public/images.small/openid.ico.gif
  291. 0  samples/{ruby-login-server → login}/public/images.small/openid.ico.png
  292. 0  samples/{ruby-login-server → login}/public/images.small/rambler.ico
  293. 0  samples/{ruby-login-server → login}/public/images.small/rambler.ico.gif
  294. 0  samples/{ruby-login-server → login}/public/images.small/rambler.ico.png
  295. 0  samples/{ruby-login-server → login}/public/images.small/technorati.ico
  296. 0  samples/{ruby-login-server → login}/public/images.small/technorati.ico.gif
  297. 0  samples/{ruby-login-server → login}/public/images.small/technorati.ico.png
  298. 0  samples/{ruby-login-server → login}/public/images.small/twitter.ico
  299. 0  samples/{ruby-login-server → login}/public/images.small/twitter.ico.gif
  300. 0  samples/{ruby-login-server → login}/public/images.small/twitter.ico.png
Sorry, we could not display the entire diff because too many files (444) changed.
28 README.md
View
@@ -31,15 +31,15 @@ If this works you are in business:
Each module has a `mvn tomcat:run` target to run individually, or you
could import them as projects into STS (use 2.8.0 or better if you
can). The apps all work together the apps running on the same port
-(8080) as `/uaa`, `/app` and `/api`. You can probably use Maven 2.2.1
-to build the code, but you need to use Maven 3 if you want to run the
-server from the command line (or run integration tests).
+(8080) as `/uaa`, `/app` and `/api`.
+
+You will need Maven 3.0.4 or newer.
### Deploy to Cloud Foundry
You can also build the app and push it to Cloud Foundry, e.g.
- $ mvn install
+ $ mvn package install
$ vmc push myuaa --path uaa/target
(If you do that, choose a unique application id, not 'myuaa'.)
@@ -67,8 +67,8 @@ Then you can try logging in with the UAA ruby gem. Make sure you have
ruby 1.9, and bundler installed, then
$ cd gem/; bundle
- $ ./bin/uaac target http://localhost:8080/uaa vmc
- $ ./bin/uaac login implicit marissa koala
+ $ ./bin/uaac target http://localhost:8080/uaa
+ $ ./bin/uaac token get marissa koala
(or leave out the username / password to be prompted).
@@ -290,17 +290,17 @@ In CloudFoundry terms
* `uaa` provides an authentication service plus authorized delegation for
back-end services and apps (by issuing OAuth2 access tokens).
-* `api` is `api.cloudfoundry.com` - it's a service which provides resources
- which other applications may wish to access on behalf of the resource
- owner (the end user).
+* `api` is a service that provides resources that other applications may
+ wish to access on behalf of the resource owner (the end user).
+
+* `app` is a webapp that needs single sign on and access to the `api`
+ service on behalf of users.
-* `app` is `code.cloudfoundry.com` or `studio.cloudfoundry.com` - a
- webapp that needs single sign on and access to the `api` service on
- behalf of users.
-
* `login` is where Cloud Foundry administrators set up their
authentication sources, e.g. LDAP/AD, SAML, OpenID (Google etc.) or
- social.
+ social. The cloudfoundry.com platform uses a different
+ implementation of the
+ [login server](https://github.com/cloudfoundry/login-server).
## UAA Server
15 common/pom.xml
View
@@ -5,7 +5,7 @@
<parent>
<groupId>org.cloudfoundry.identity</groupId>
<artifactId>cloudfoundry-identity-parent</artifactId>
- <version>1.2.6</version>
+ <version>1.3.1</version>
<relativePath>..</relativePath>
</parent>
@@ -196,6 +196,11 @@
<version>2.5</version>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjrt</artifactId>
+ </dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
@@ -258,14 +263,6 @@
<scope>test</scope>
</dependency>
- <!-- Only needed for CC token serialization PoC -->
- <dependency>
- <groupId>org.jruby</groupId>
- <artifactId>jruby</artifactId>
- <version>1.6.5</version>
- <scope>test</scope>
- </dependency>
-
</dependencies>
</project>
1  common/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEvent.java
View
@@ -16,6 +16,7 @@
* Used when retrieving audit data from the audit service
*/
public class AuditEvent {
+
private final AuditEventType type;
private final String principalId;
private final String origin;
12 common/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java
View
@@ -16,16 +16,24 @@
* Allows audit events to be classified by type.
*
* @author Luke Taylor
+ * @author Dave Syer
*/
public enum AuditEventType {
+
// Do not change the code values, as these are used in the database.
UserAuthenticationSuccess (0),
UserAuthenticationFailure (1),
UserNotFound (2),
- PasswordChanged (3),
+ PasswordChangeSuccess (3),
PrincipalAuthenticationSuccess (4),
PrincipalAuthenticationFailure (5),
- PrincipalNotFound (6);
+ PrincipalNotFound (6),
+ PasswordChangeFailure (7),
+ SecretChangeSuccess (8),
+ SecretChangeFailure (9),
+ ClientCreateSuccess (10),
+ ClientUpdateSuccess (11),
+ ClientDeleteSuccess (12);
private final int code;
68 common/src/main/java/org/cloudfoundry/identity/uaa/audit/JdbcAuditService.java
View
@@ -12,8 +12,6 @@
*/
package org.cloudfoundry.identity.uaa.audit;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
@@ -21,13 +19,8 @@
import javax.sql.DataSource;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
-import org.springframework.security.crypto.codec.Base64;
-import org.springframework.security.crypto.codec.Utf8;
-import org.springframework.util.Assert;
/**
*
@@ -40,48 +33,9 @@
public JdbcAuditService(DataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
-
- @Override
- public void userAuthenticationSuccess(UaaUser user, UaaAuthenticationDetails details) {
- Assert.notNull(user, "UaaUser cannot be null");
- createAuditRecord(user.getId(), AuditEventType.UserAuthenticationSuccess, getOrigin(details), user.getUsername());
- }
-
- // Ideally we want to get to the point where details is never null, but this isn't currently possible
- // due to some OAuth authentication scenarios which don't set it.
- private String getOrigin(UaaAuthenticationDetails details) {
- return details == null ? "unknown" : details.getOrigin();
- }
-
- @Override
- public void userAuthenticationFailure(UaaUser user, UaaAuthenticationDetails details) {
- if (user==null) {
- userNotFound("<UNKNOWN>", details);
- return;
- }
- createAuditRecord(user.getId(), AuditEventType.UserAuthenticationFailure, getOrigin(details), user.getUsername());
- }
-
- @Override
- public void userNotFound(String name, UaaAuthenticationDetails details) {
- try {
- // Store hash of name, to conceal accidental entry of sensitive info (e.g. password)
- name = Utf8.decode(Base64.encode(MessageDigest.getInstance("SHA-1").digest(Utf8.encode(name))));
- }
- catch (NoSuchAlgorithmException shouldNeverHappen) {
- name = "NOSHA";
- }
- createAuditRecord(name, AuditEventType.UserNotFound, getOrigin(details), "");
- }
-
- @Override
- public void principalAuthenticationFailure(String name, UaaAuthenticationDetails details) {
- createAuditRecord(name, AuditEventType.PrincipalAuthenticationFailure, getOrigin(details));
- }
-
- @Override
- public void principalNotFound(String name, UaaAuthenticationDetails details) {
- createAuditRecord(name, AuditEventType.PrincipalNotFound, getOrigin(details));
+
+ protected JdbcTemplate getJdbcTemplate() {
+ return template;
}
@Override
@@ -90,14 +44,16 @@ public void principalNotFound(String name, UaaAuthenticationDetails details) {
"principal_id=? and created > ? order by created desc", new AuditEventRowMapper(), principal, new Timestamp(after));
}
- private void createAuditRecord(String principal_id, AuditEventType type, String origin) {
- template.update("insert into sec_audit (principal_id, event_type, origin) values (?,?,?)",
- principal_id, type.getCode(), origin);
- }
-
- private void createAuditRecord(String principal_id, AuditEventType type, String origin, String data) {
+ @Override
+ public void log(AuditEvent auditEvent) {
+ String origin = auditEvent.getOrigin();
+ String data = auditEvent.getData();
+ origin = origin==null ? "" : origin;
+ origin = origin.length()>255 ? origin.substring(0, 255) : origin;
+ data = data==null ? "" : data;
+ data = data.length()>255 ? data.substring(0, 255) : data;
template.update("insert into sec_audit (principal_id, event_type, origin, event_data) values (?,?,?,?)",
- principal_id, type.getCode(), origin, data);
+ auditEvent.getPrincipalId(), auditEvent.getType().getCode(), auditEvent.getOrigin(), auditEvent.getData());
}
private class AuditEventRowMapper implements RowMapper<AuditEvent> {
82 common/src/main/java/org/cloudfoundry/identity/uaa/audit/JdbcFailedLoginCountingAuditService.java
View
@@ -12,33 +12,22 @@
*/
package org.cloudfoundry.identity.uaa.audit;
-import java.sql.ResultSet;
-import java.sql.SQLException;
import java.sql.Timestamp;
-import java.util.List;
import javax.sql.DataSource;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.util.Assert;
-
/**
* An audit service that subscribes to audit events but only saves enough data to answer queries about consecutive
* failed logins.
*
* @author Dave Syer
*/
-public class JdbcFailedLoginCountingAuditService implements UaaAuditService {
-
- private final JdbcTemplate template;
+public class JdbcFailedLoginCountingAuditService extends JdbcAuditService {
private int saveDataPeriodMillis = 2 * 3600 * 1000; // 2hr
public JdbcFailedLoginCountingAuditService(DataSource dataSource) {
- this.template = new JdbcTemplate(dataSource);
+ super(dataSource);
}
/**
@@ -47,61 +36,22 @@ public JdbcFailedLoginCountingAuditService(DataSource dataSource) {
public void setSaveDataPeriodMillis(int saveDataPeriodMillis) {
this.saveDataPeriodMillis = saveDataPeriodMillis;
}
-
+
@Override
- public void userAuthenticationSuccess(UaaUser user, UaaAuthenticationDetails details) {
- Assert.notNull(user, "UaaUser cannot be null");
- // Reset the data for this user
- template.update("delete from sec_audit where principal_id=?", user.getId());
- }
-
- // Ideally we want to get to the point where details is never null, but this isn't currently possible
- // due to some OAuth authentication scenarios which don't set it.
- private String getOrigin(UaaAuthenticationDetails details) {
- return details == null ? "unknown" : details.getOrigin();
- }
-
- @Override
- public void userAuthenticationFailure(UaaUser user, UaaAuthenticationDetails details) {
- if (user == null) {
- return;
+ public void log(AuditEvent auditEvent) {
+ switch (auditEvent.getType()) {
+ case UserAuthenticationSuccess:
+ case PasswordChangeSuccess:
+ getJdbcTemplate().update("delete from sec_audit where principal_id=?", auditEvent.getPrincipalId());
+ break;
+ case UserAuthenticationFailure:
+ getJdbcTemplate().update("delete from sec_audit where created < ?", new Timestamp(System.currentTimeMillis()
+ - saveDataPeriodMillis));
+ super.log(auditEvent);
+ break;
+ default:
+ break;
}
- template.update("delete from sec_audit where created < ?", new Timestamp(System.currentTimeMillis()
- - saveDataPeriodMillis));
- template.update("insert into sec_audit (principal_id, event_type, origin, event_data) values (?,?,?,?)",
- user.getId(), AuditEventType.UserAuthenticationFailure.getCode(), getOrigin(details), user.getUsername());
- }
-
- @Override
- public void userNotFound(String name, UaaAuthenticationDetails details) {
}
- @Override
- public void principalAuthenticationFailure(String name, UaaAuthenticationDetails details) {
- }
-
- @Override
- public void principalNotFound(String name, UaaAuthenticationDetails details) {
- }
-
- @Override
- public List<AuditEvent> find(String principal, long after) {
- return template.query("select event_type, principal_id, origin, event_data, created from sec_audit where "
- + "principal_id=? and created > ? order by created desc", new AuditEventRowMapper(), principal,
- new Timestamp(after));
- }
-
- private class AuditEventRowMapper implements RowMapper<AuditEvent> {
- @Override
- public AuditEvent mapRow(ResultSet rs, int rowNum) throws SQLException {
- String principalId = rs.getString(2);
- principalId = principalId == null ? null : principalId.trim();
- String origin = rs.getString(3);
- origin = origin == null ? null : origin.trim();
- String data = rs.getString(4);
- data = data == null ? null : data.trim();
- return new AuditEvent(AuditEventType.fromCode(rs.getInt(1)), principalId, origin, data, rs.getTimestamp(5)
- .getTime());
- }
- }
}
71 common/src/main/java/org/cloudfoundry/identity/uaa/audit/LoggingAuditService.java
View
@@ -17,8 +17,6 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.support.MetricType;
@@ -33,6 +31,7 @@
*/
@ManagedResource
public class LoggingAuditService implements UaaAuditService {
+
private final Log logger = LogFactory.getLog("UAA.Audit");
private AtomicInteger userAuthenticationCount = new AtomicInteger();
@@ -45,6 +44,10 @@
private AtomicInteger principalNotFoundCount = new AtomicInteger();
+ private AtomicInteger passwordChanges = new AtomicInteger();
+
+ private AtomicInteger passwordFailures = new AtomicInteger();
+
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "User Not Found Count")
public int getUserNotFoundCount() {
return userNotFoundCount.get();
@@ -70,39 +73,54 @@ public int getPrincipalNotFoundCount() {
return principalNotFoundCount.get();
}
- @Override
- public void userAuthenticationSuccess(UaaUser user, UaaAuthenticationDetails details) {
- userAuthenticationCount.incrementAndGet();
- log("User authenticated: " + user.getId() + ", " + user.getUsername());
- }
-
- @Override
- public void userAuthenticationFailure(UaaUser user, UaaAuthenticationDetails details) {
- userAuthenticationFailureCount.incrementAndGet();
- log("Authentication failed, user: " + user.getId() + ", " + user.getUsername());
+ @ManagedMetric(metricType = MetricType.COUNTER, displayName = "User Password Change Count (Since Startup)")
+ public int getUserPasswordChanges() {
+ return passwordChanges.get();
}
- @Override
- public void userNotFound(String name, UaaAuthenticationDetails details) {
- userNotFoundCount.incrementAndGet();
- log("Attempt to login as non-existent user: " + name);
+ @ManagedMetric(metricType = MetricType.COUNTER, displayName = "User Password Change Failure Count (Since Startup)")
+ public int getUserPasswordFailures() {
+ return passwordFailures.get();
}
@Override
- public void principalAuthenticationFailure(String name, UaaAuthenticationDetails details) {
- principalAuthenticationFailureCount.incrementAndGet();
- log("Authentication failed, principal: " + name);
+ public List<AuditEvent> find(String principal, long after) {
+ throw new UnsupportedOperationException("This implementation does not store data");
}
@Override
- public void principalNotFound(String name, UaaAuthenticationDetails details) {
- principalNotFoundCount.incrementAndGet();
- log("Authentication failed, principal not found: " + name);
+ public void log(AuditEvent auditEvent) {
+ updateCounters(auditEvent);
+ log(String.format("%s ('%s'): principal=%s, origin=[%s]", auditEvent.getType().name(), auditEvent.getData(),
+ auditEvent.getPrincipalId(), auditEvent.getOrigin()));
}
- @Override
- public List<AuditEvent> find(String principal, long after) {
- throw new UnsupportedOperationException("This implementation does not store data");
+ private void updateCounters(AuditEvent auditEvent) {
+ switch (auditEvent.getType()) {
+ case PasswordChangeSuccess:
+ passwordChanges.incrementAndGet();
+ break;
+ case PasswordChangeFailure:
+ passwordFailures.incrementAndGet();
+ break;
+ case UserAuthenticationSuccess:
+ userAuthenticationCount.incrementAndGet();
+ break;
+ case UserAuthenticationFailure:
+ userAuthenticationFailureCount.incrementAndGet();
+ break;
+ case UserNotFound:
+ userNotFoundCount.incrementAndGet();
+ break;
+ case PrincipalAuthenticationFailure:
+ principalAuthenticationFailureCount.incrementAndGet();
+ break;
+ case PrincipalNotFound:
+ principalNotFoundCount.incrementAndGet();
+ break;
+ default:
+ break;
+ }
}
private void log(String msg) {
@@ -112,7 +130,8 @@ private void log(String msg) {
output.append(msg);
output.append("\n\n************************************************************\n");
logger.trace(output.toString());
- } else {
+ }
+ else {
logger.info(msg);
}
}
29 common/src/main/java/org/cloudfoundry/identity/uaa/audit/UaaAuditService.java
View
@@ -14,30 +14,29 @@
import java.util.List;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
/**
* Service interface which handles the different types of audit event raised by the system.
+ *
+ * @author Luke Talyor
+ * @author Dave Syer
*/
public interface UaaAuditService {
+
/**
- * Authentication of a specific user, i.e. a person
+ * Find audit events relating to the specified principal since the time provided.
+ *
+ * @param principal the principal name to search for
+ * @param after epoch in milliseconds
+ * @return audit events relating to the principal
*/
- void userAuthenticationSuccess(UaaUser user, UaaAuthenticationDetails details);
-
- void userAuthenticationFailure(UaaUser user, UaaAuthenticationDetails details);
-
- void userNotFound(String name, UaaAuthenticationDetails details);
+ List<AuditEvent> find(String principal, long after);
/**
- * Authentication of any other (non-user) principal.
+ * Log an event.
+ *
+ * @param auditEvent the audit event to log
*/
-// void principalAuthenticationSuccess(String name);
+ void log(AuditEvent auditEvent);
- void principalAuthenticationFailure(String name, UaaAuthenticationDetails details);
-
- void principalNotFound(String name, UaaAuthenticationDetails details);
-
- List<AuditEvent> find(String principal, long after);
}
103 common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AbstractUaaEvent.java
View
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.audit.event;
+
+import java.security.Principal;
+import java.util.Map;
+
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
+import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+
+/**
+ * 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 ObjectMapper mapper = new ObjectMapper();
+
+ {
+ mapper.setSerializationConfig(mapper.getSerializationConfig().withSerializationInclusion(Inclusion.NON_NULL));
+ }
+
+ protected AbstractUaaEvent(Object source) {
+ super(source);
+ }
+
+ public void process(UaaAuditService auditor) {
+ auditor.log(getAuditEvent());
+ }
+
+ protected AuditEvent createAuditRecord(String principalId, AuditEventType type, String origin) {
+ return new AuditEvent(type, principalId, origin, null, System.currentTimeMillis());
+ }
+
+ protected AuditEvent createAuditRecord(String principalId, AuditEventType type, String origin, String data) {
+ return new AuditEvent(type, principalId, origin, data, System.currentTimeMillis());
+ }
+
+ // Ideally we want to get to the point where details is never null, but this isn't currently possible
+ // due to some OAuth authentication scenarios which don't set it.
+ protected String getOrigin(Principal principal) {
+
+ if (principal instanceof Authentication) {
+
+ Authentication caller = (Authentication) principal;
+ StringBuilder builder = new StringBuilder();
+ if (caller instanceof OAuth2Authentication) {
+ OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) caller;
+ builder.append("client=").append(oAuth2Authentication.getAuthorizationRequest().getClientId());
+ if (!oAuth2Authentication.isClientOnly()) {
+ builder.append(", ").append("user=").append(oAuth2Authentication.getName());
+ }
+ }
+ else {
+ builder.append("caller=").append(caller.getName()).append(", ");
+ }
+
+ if (caller.getDetails() != null) {
+ builder.append(", details=(");
+ try {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> map = mapper.convertValue(caller.getDetails(), Map.class);
+ if (map.containsKey("remoteAddress")) {
+ builder.append("remoteAddress=").append(map.get("remoteAddress")).append(", ");
+ }
+ builder.append("type=").append(caller.getDetails().getClass().getSimpleName());
+ }
+ catch (Exception e) {
+ // ignore
+ builder.append(caller.getDetails());
+ }
+ builder.append(")");
+ }
+ return builder.toString();
+
+ }
+
+ return principal == null ? null : principal.getName();
+
+ }
+
+ public abstract AuditEvent getAuditEvent();
+
+}
44 common/src/main/java/org/cloudfoundry/identity/uaa/audit/event/AuditListener.java
View
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.audit.event;
+
+import org.cloudfoundry.identity.uaa.audit.LoggingAuditService;
+import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
+import org.springframework.context.ApplicationListener;
+import org.springframework.util.Assert;
+
+/**
+ * Spring {@code ApplicationListener} which picks up the listens for {@code AbstractUaaEvent}s and passes the relevant
+ * information to the {@code UaaAuditService}.
+ *
+ * @author Luke Taylor
+ * @author Dave Syer
+ */
+public class AuditListener implements ApplicationListener<AbstractUaaEvent> {
+ private final UaaAuditService uaaAuditService;
+
+ public AuditListener() {
+ uaaAuditService = new LoggingAuditService();
+ }
+
+ public AuditListener(UaaAuditService auditor) {
+ Assert.notNull(auditor);
+ this.uaaAuditService = auditor;
+ }
+
+ @Override
+ public void onApplicationEvent(AbstractUaaEvent event) {
+ event.process(uaaAuditService);
+ }
+
+}
6 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/AuthzAuthenticationFilter.java
View
@@ -72,10 +72,10 @@
private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
private Set<String> methods = Collections.singleton(HttpMethod.POST.toString());
-
+
/**
* The filter fails on requests that don't have one of these HTTP methods.
- *
+ *
* @param methods the methods to set (defaults to POST)
*/
public void setMethods(Set<String> methods) {
@@ -222,7 +222,7 @@ public boolean hasMoreElements() {
@Override
public String nextElement() {
- Object ret = underlying.nextElement();
+ underlying.nextElement();
return "application/json";
}
35 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/UaaAuthenticationDetails.java
View
@@ -12,6 +12,8 @@
*/
package org.cloudfoundry.identity.uaa.authentication;
+import java.io.Serializable;
+
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
@@ -22,16 +24,22 @@
* @author Luke Taylor
* @author Dave Syer
*/
-public class UaaAuthenticationDetails {
+public class UaaAuthenticationDetails implements Serializable {
private final String origin;
private String sessionId;
+ private String clientId;
+
public UaaAuthenticationDetails(HttpServletRequest request) {
WebAuthenticationDetails webAuthenticationDetails = new WebAuthenticationDetails(request);
this.origin = webAuthenticationDetails.getRemoteAddress();
this.sessionId = webAuthenticationDetails.getSessionId();
+ String clientId = request.getParameter("client_id");
+ if (clientId != null) {
+ this.clientId = clientId;
+ }
}
public String getOrigin() {
@@ -41,4 +49,29 @@ public String getOrigin() {
public String getSessionId() {
return sessionId;
}
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (origin != null) {
+ sb.append("remoteAddress=").append(origin);
+ }
+ if (clientId!=null) {
+ if (sb.length()>0) {
+ sb.append(", ");
+ }
+ sb.append("clientId=").append(clientId);
+ }
+ if (sessionId!=null) {
+ if (sb.length()>0) {
+ sb.append(", ");
+ }
+ sb.append("sessionId=").append(sessionId);
+ }
+ return sb.toString();
+ }
}
12 ...ity/uaa/event/AbstractUaaAuthenticationEvent.java → ...ication/event/AbstractUaaAuthenticationEvent.java
View
@@ -10,8 +10,10 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.event;
+package org.cloudfoundry.identity.uaa.authentication.event;
+import org.cloudfoundry.identity.uaa.audit.event.AbstractUaaEvent;
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.springframework.security.core.Authentication;
/**
@@ -26,5 +28,13 @@
Authentication getAuthentication() {
return (Authentication)source;
}
+
+ protected String getOrigin(UaaAuthenticationDetails details) {
+ return details == null ? "unknown" : details.toString();
+ }
+
+ UaaAuthenticationDetails getAuthenticationDetails() {
+ return (UaaAuthenticationDetails) getAuthentication().getDetails();
+ }
}
35 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaPrincipalEvent.java
View
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.authentication.event;
+
+import org.cloudfoundry.identity.uaa.audit.event.AbstractUaaEvent;
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+
+/**
+ * @author Dave Syer
+ */
+abstract class AbstractUaaPrincipalEvent extends AbstractUaaEvent {
+
+ AbstractUaaPrincipalEvent(UaaAuthenticationDetails details) {
+ super(details);
+ }
+
+ protected String getOrigin(UaaAuthenticationDetails details) {
+ return details == null ? "unknown" : details.getOrigin();
+ }
+
+ UaaAuthenticationDetails getAuthenticationDetails() {
+ return (UaaAuthenticationDetails)source;
+ }
+
+}
50 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/BadCredentialsListener.java
View
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.authentication.event;
+
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.context.ApplicationListener;
+import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+/**
+ * Spring {@code ApplicationListener} which picks up the listens for Spring Security events and relays them.
+ *
+ * @author Dave Syer
+ */
+public class BadCredentialsListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent>,
+ ApplicationEventPublisherAware {
+
+ private ApplicationEventPublisher publisher;
+
+ @Override
+ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
+ this.publisher = publisher;
+ }
+
+ @Override
+ public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
+ AuthenticationFailureBadCredentialsEvent bce = (AuthenticationFailureBadCredentialsEvent) event;
+ String principal = bce.getAuthentication().getName();
+ UaaAuthenticationDetails details = (UaaAuthenticationDetails) bce.getAuthentication().getDetails();
+ if (bce.getException() instanceof UsernameNotFoundException) {
+ publisher.publishEvent(new PrincipalNotFoundEvent(principal, details));
+ }
+ else {
+ publisher.publishEvent(new PrincipalAuthenticationFailureEvent(principal, details));
+ }
+ }
+
+}
39 ...rc/main/java/org/cloudfoundry/identity/uaa/authentication/event/PrincipalAuthenticationFailureEvent.java
View
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.authentication.event;
+
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+
+/**
+ * Event which indicates that a non-user principal tried to authenticate and failed.
+ *
+ * @author Dave Syer
+ */
+public class PrincipalAuthenticationFailureEvent extends AbstractUaaPrincipalEvent {
+
+ private String name;
+
+ public PrincipalAuthenticationFailureEvent(String name, UaaAuthenticationDetails details) {
+ super(details);
+ this.name = name;
+ }
+
+ @Override
+ public AuditEvent getAuditEvent() {
+ return createAuditRecord(name, AuditEventType.PrincipalAuthenticationFailure,
+ getOrigin(getAuthenticationDetails()));
+ }
+
+}
38 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/PrincipalNotFoundEvent.java
View
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package org.cloudfoundry.identity.uaa.authentication.event;
+
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+
+/**
+ * Event which indicates that a non-user principal tried to authenticate but was not found.
+ *
+ * @author Dave Syer
+ */
+public class PrincipalNotFoundEvent extends AbstractUaaPrincipalEvent {
+
+ private String name;
+
+ public PrincipalNotFoundEvent(String name, UaaAuthenticationDetails details) {
+ super(details);
+ this.name = name;
+ }
+
+ @Override
+ public AuditEvent getAuditEvent() {
+ return createAuditRecord(name, AuditEventType.PrincipalNotFound, getOrigin(getAuthenticationDetails()));
+ }
+
+}
15 ...ity/uaa/event/UserAuthenticationFailureEvent.java → ...ication/event/UserAuthenticationFailureEvent.java
View
@@ -10,10 +10,10 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.event;
+package org.cloudfoundry.identity.uaa.authentication.event;
-import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
@@ -35,7 +35,12 @@ public UserAuthenticationFailureEvent(UaaUser user, Authentication authenticatio
}
@Override
- public void process(UaaAuditService auditor) {
- auditor.userAuthenticationFailure(user, (UaaAuthenticationDetails) getAuthentication().getDetails());
+ public AuditEvent getAuditEvent() {
+ if (user == null) {
+ return createAuditRecord("<UNKNOWN>", AuditEventType.UserNotFound, getOrigin(getAuthenticationDetails()),
+ user.getUsername());
+ }
+ return createAuditRecord(user.getId(), AuditEventType.UserAuthenticationFailure,
+ getOrigin(getAuthenticationDetails()), user.getUsername());
}
}
14 ...ity/uaa/event/UserAuthenticationSuccessEvent.java → ...ication/event/UserAuthenticationSuccessEvent.java
View
@@ -10,15 +10,17 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.event;
+package org.cloudfoundry.identity.uaa.authentication.event;
-import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.springframework.security.core.Authentication;
+import org.springframework.util.Assert;
/**
* @author Luke Taylor
+ * @author Dave Syer
*/
public class UserAuthenticationSuccessEvent extends AbstractUaaAuthenticationEvent {
private final UaaUser user;
@@ -29,7 +31,9 @@ public UserAuthenticationSuccessEvent(UaaUser user, Authentication authenticatio
}
@Override
- public void process(UaaAuditService auditor) {
- auditor.userAuthenticationSuccess(user, (UaaAuthenticationDetails) getAuthentication().getDetails());
+ public AuditEvent getAuditEvent() {
+ Assert.notNull(user, "UaaUser cannot be null");
+ return createAuditRecord(user.getId(), AuditEventType.UserAuthenticationSuccess,
+ getOrigin(getAuthenticationDetails()), user.getUsername());
}
}
27 ...foundry/identity/uaa/event/UserNotFoundEvent.java → ...y/uaa/authentication/event/UserNotFoundEvent.java
View
@@ -10,11 +10,16 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.event;
+package org.cloudfoundry.identity.uaa.authentication.event;
-import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.cloudfoundry.identity.uaa.audit.AuditEvent;
+import org.cloudfoundry.identity.uaa.audit.AuditEventType;
import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.crypto.codec.Utf8;
/**
* Event which indicates that someone tried to authenticate as a non-existent user.
@@ -28,7 +33,19 @@ public UserNotFoundEvent(Authentication authentication) {
}
@Override
- public void process(UaaAuditService auditor) {
- auditor.userNotFound(getAuthentication().getName(), (UaaAuthenticationDetails) getAuthentication().getDetails());
+ public AuditEvent getAuditEvent() {
+
+ String name = getAuthentication().getName();
+
+ try {
+ // Store hash of name, to conceal accidental entry of sensitive info (e.g. password)
+ name = Utf8.decode(Base64.encode(MessageDigest.getInstance("SHA-1").digest(Utf8.encode(name))));
+ }
+ catch (NoSuchAlgorithmException shouldNeverHappen) {
+ name = "NOSHA";
+ }
+
+ return createAuditRecord(name, AuditEventType.UserNotFound, getOrigin(getAuthenticationDetails()), "");
+
}
}
2  common/src/main/java/org/cloudfoundry/identity/uaa/authentication/login/LoginInfoEndpoint.java
View
@@ -62,7 +62,7 @@ public void setPrompts(List<Prompt> prompts) {
this.prompts = prompts;
}
- @RequestMapping(value = { "/login_info", "/login" })
+ @RequestMapping(value = { "/info", "/login" })
public String loginInfo(Model model, Principal principal) {
Map<String, String[]> map = new LinkedHashMap<String, String[]>();
for (Prompt prompt : prompts) {
35 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java
View
@@ -22,15 +22,18 @@
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.event.UserAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.event.UserAuthenticationSuccessEvent;
-import org.cloudfoundry.identity.uaa.event.UserNotFoundEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationFailureEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.UserNotFoundEvent;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
+import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
+import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
@@ -72,7 +75,9 @@ public Authentication authenticate(Authentication req) throws AuthenticationExce
logger.debug("Processing authentication request for " + req.getName());
if (req.getCredentials() == null) {
- throw new BadCredentialsException("No password supplied");
+ BadCredentialsException e = new BadCredentialsException("No password supplied");
+ publish(new AuthenticationFailureBadCredentialsEvent(req, e));
+ throw e;
}
UaaUser user;
@@ -88,28 +93,36 @@ public Authentication authenticate(Authentication req) throws AuthenticationExce
if (!accountLoginPolicy.isAllowed(user, req)) {
logger.warn("Login policy rejected authentication for " + user.getUsername() + ", " + user.getId()
+ ". Ignoring login request.");
- // TODO: We should perhaps have another audit event type here
- // since this will not be logged as an authentication failure.
- throw new BadCredentialsException("Login policy rejected authentication");
+ BadCredentialsException e = new BadCredentialsException("Login policy rejected authentication");
+ publish(new AuthenticationFailureLockedEvent(req, e));
+ throw e;
}
if (passwordMatches) {
logger.debug("Password successfully matched");
Authentication success = new UaaAuthentication(new UaaPrincipal(user),
user.getAuthorities(), (UaaAuthenticationDetails) req.getDetails());
- eventPublisher.publishEvent(new UserAuthenticationSuccessEvent(user, success));
+ publish(new UserAuthenticationSuccessEvent(user, success));
return success;
}
if (user == dummyUser) {
logger.debug("No user named '" + req.getName() + "' was found");
- eventPublisher.publishEvent(new UserNotFoundEvent(req));
+ publish(new UserNotFoundEvent(req));
} else {
logger.debug("Password did not match for user " + req.getName());
- eventPublisher.publishEvent(new UserAuthenticationFailureEvent(user, req));
+ publish(new UserAuthenticationFailureEvent(user, req));
+ }
+ BadCredentialsException e = new BadCredentialsException("Bad credentials");
+ publish(new AuthenticationFailureBadCredentialsEvent(req, e));
+ throw e;
+ }
+
+ private void publish(ApplicationEvent event) {
+ if (eventPublisher!=null) {
+ eventPublisher.publishEvent(event);
}
- throw new BadCredentialsException("Bad credentials");
}
@Override
28 common/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java
View
@@ -8,11 +8,10 @@
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.event.UserAuthenticationSuccessEvent;
-import org.cloudfoundry.identity.uaa.scim.ScimUserBootstrap;
-import org.cloudfoundry.identity.uaa.user.UaaAuthority;
+import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
+import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authentication.AuthenticationManager;
@@ -31,8 +30,6 @@
private ApplicationEventPublisher eventPublisher;
- private ScimUserBootstrap scimUserBootstrap;
-
private UaaUserDatabase userDatabase;
boolean addNewAccounts = false;
@@ -55,15 +52,6 @@ public void setApplicationEventPublisher(ApplicationEventPublisher eventPublishe
}
/**
- * If set this bootstrap helper will be used to register new accounts.
- *
- * @param scimUserBootstrap the scim user bootstrap to set
- */
- public void setScimUserBootstrap(ScimUserBootstrap scimUserBootstrap) {
- this.scimUserBootstrap = scimUserBootstrap;
- }
-
- /**
* @param userDatabase the userDatabase to set
*/
public void setUserDatabase(UaaUserDatabase userDatabase) {
@@ -94,9 +82,9 @@ public Authentication authenticate(Authentication request) throws Authentication
}
catch (UsernameNotFoundException e) {
// Not necessarily fatal
- if (scimUserBootstrap != null && addNewAccounts) {
+ if (addNewAccounts) {
// Register new users automatically
- scimUserBootstrap.addUser(user);
+ publish(new NewUserAuthenticatedEvent(user));
try {
user = userDatabase.retrieveUserByName(user.getUsername());
}
@@ -110,7 +98,7 @@ public Authentication authenticate(Authentication request) throws Authentication
}
Authentication success = new UaaAuthentication(new UaaPrincipal(user), user.getAuthorities(),
(UaaAuthenticationDetails) req.getDetails());
- eventPublisher.publishEvent(new UserAuthenticationSuccessEvent(user, success));
+ publish(new UserAuthenticationSuccessEvent(user, success));
return success;
}
}
@@ -120,6 +108,12 @@ public Authentication authenticate(Authentication request) throws Authentication
}
+ protected void publish(ApplicationEvent event) {
+ if (eventPublisher != null) {
+ eventPublisher.publishEvent(event);
+ }
+ }
+
protected UaaUser getUser(AuthzAuthenticationRequest req, Map<String, String> info) {
String name = req.getName();
String email = info.get("email");
19 ...dfoundry/identity/uaa/event/AbstractUaaEvent.java → ...entication/manager/NewUserAuthenticatedEvent.java
View
@@ -10,21 +10,24 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.event;
-import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
+package org.cloudfoundry.identity.uaa.authentication.manager;
+
+import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.springframework.context.ApplicationEvent;
/**
- * Base class for all UAA events.
+ * @author Dave Syer
*
- * @author Luke Taylor
*/
-public abstract class AbstractUaaEvent extends ApplicationEvent {
+public class NewUserAuthenticatedEvent extends ApplicationEvent {
- AbstractUaaEvent(Object source) {
- super(source);
+ public NewUserAuthenticatedEvent(UaaUser user) {
+ super(user);
+ }
+
+ public UaaUser getUser() {
+ return (UaaUser) source;
}
- public abstract void process(UaaAuditService auditor);
}
170 common/src/main/java/org/cloudfoundry/identity/uaa/client/ClientAuthenticationFilter.java
View
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+package org.cloudfoundry.identity.uaa.client;
+
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.oauth2.client.UserRedirectRequiredException;
+import org.springframework.security.oauth2.client.http.AccessTokenRequiredException;
+import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * An authentication filter for remote identity providers. Intended to be used with Spring OAuth (1 or 2), since it is
+ * aware of the redirect protocols employed by those frameworks. If used in the PRE_AUTH_FILTER position of a regular
+ * Spring Security filter chain the user will be redirected to the remote provider to approve the access and return with
+ * a valid access token. There are 2 main strategies to provide:
+ *
+ * <ul>
+ * <li> {@link #setPreAuthenticatedPrincipalSource(PreAuthenticatedPrincipalSource) PreAuthenticatedPrincipalSource}
+ * (mandatory) provides a {@link Principal} that can be authenticated by the authentication manager. An example would be
+ * to contact the user info endpoint in a remote social provider and populate an {@link Authentication} token with the
+ * user's profile data. The principal is wrapped by</li>
+ * <li>{@link #setAuthenticationManager(AuthenticationManager) Authentication manager} is optional and defaults to a
+ * value that tries very hard to authenticate everything it sees, on the assumption that it was obtained from a trusted
+ * ID provider.</li>
+ * </ul>
+ *
+ * To ensure that the default authentication manager successfully authenticates the user, the principal source should
+ * create a principal that itself is an {@link Authentication} and is already authenticated. If you are not using the
+ * default authentication manager then you are free to authenticate any way you like (hence there is collaboration
+ * between the principal source and authentication manager, and the principal source can create an object of any type
+ * that is understood by the authentication manager).
+ *
+ * @author Dave Syer
+ *
+ */
+public class ClientAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
+
+ private PreAuthenticatedPrincipalSource<?> principalSource;
+
+ private boolean oauthAvailable = false;
+
+ private boolean oauth2Available = false;
+
+ /**
+ * @param socialClientUserDetailsSource the socialClientUserDetailsSource to set
+ */
+ public void setPreAuthenticatedPrincipalSource(PreAuthenticatedPrincipalSource<?> principalSource) {
+ this.principalSource = principalSource;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ Assert.state(principalSource != null, "User info source must be provided");
+ super.afterPropertiesSet();
+ try {
+ oauth2Available = ClassUtils.isPresent(AccessTokenRequiredException.class.getName(),
+ ClassUtils.getDefaultClassLoader());
+ }
+ catch (NoClassDefFoundError e) {
+ // ignore
+ }
+ try {
+ oauthAvailable = ClassUtils.isPresent(
+ org.springframework.security.oauth.consumer.AccessTokenRequiredException.class.getName(),
+ ClassUtils.getDefaultClassLoader());
+ }
+ catch (NoClassDefFoundError e) {
+ // ignore
+ }
+ }
+
+ public ClientAuthenticationFilter(String defaultFilterProcessesUrl) {
+ setAuthenticationManager(new DefaultFriendlyAuthenticationManager());
+ }
+
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException failed) {
+ // Need to force a redirect via the OAuth client filter, so rethrow here if OAuth related
+ if (oauth2Available && failed instanceof SocialRedirectException) {
+ throw ((SocialRedirectException) failed).getUserRedirectException();
+ }
+ if (oauthAvailable
+ && failed instanceof org.springframework.security.oauth.consumer.AccessTokenRequiredException) {
+ throw failed;
+ }
+ else {
+ // If the exception is not a Spring Security exception this will result in a default error page
+ super.unsuccessfulAuthentication(request, response, failed);
+ }
+ }
+
+ @Override
+ protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
+ try {
+ Object result = principalSource.getPrincipal();
+ return result;
+ }
+ catch (UserRedirectRequiredException e) {
+ throw new SocialRedirectException(e);
+ }
+ }
+
+ @Override
+ protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
+ return "N/A";
+ }
+
+ private static class DefaultFriendlyAuthenticationManager implements AuthenticationManager {
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+
+ boolean authenticated = authentication.isAuthenticated();
+
+ // If not already authenticated (the default) from the parent class
+ if (authentication instanceof PreAuthenticatedAuthenticationToken && !authenticated) {
+
+ PreAuthenticatedAuthenticationToken preAuth = (PreAuthenticatedAuthenticationToken) authentication;
+ // Look inside the principal and see if that was marked as authenticated
+ if (preAuth.getPrincipal() instanceof Authentication) {
+ Authentication principal = (Authentication) preAuth.getPrincipal();
+ preAuth = new PreAuthenticatedAuthenticationToken(principal, preAuth.getCredentials(), principal.getAuthorities());
+ authenticated = principal.isAuthenticated();
+ }
+ preAuth.setAuthenticated(authenticated);
+
+ authentication = preAuth;
+
+ }
+
+ return authentication;
+
+ }
+
+ }
+
+ private static class SocialRedirectException extends AuthenticationException {
+
+ public SocialRedirectException(UserRedirectRequiredException e) {
+ super("Social user details extraction failed", e);
+ }
+
+ public UserRedirectRequiredException getUserRedirectException() {
+ return (UserRedirectRequiredException) getCause();
+ }
+
+ }
+
+}
50 common/src/main/java/org/cloudfoundry/identity/uaa/client/OAuth2AccessTokenSource.java
View
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package org.cloudfoundry.identity.uaa.client;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.security.oauth2.client.OAuth2RestOperations;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.util.Assert;
+
+/**
+ *
+ * @author Dave Syer
+ *
+ */
+public class OAuth2AccessTokenSource implements InitializingBean, PreAuthenticatedPrincipalSource<String> {
+
+ private OAuth2RestOperations restTemplate;
+
+ /**
+ * A rest template to be used to contact the remote user info endpoint. Normally an instance of
+ * {@link OAuth2RestTemplate}.
+ *
+ * @param restTemplate a rest template
+ */
+ public void setRestTemplate(OAuth2RestOperations restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ Assert.state(restTemplate != null, "RestTemplate URL must be provided");
+ }
+
+ @Override
+ public String getPrincipal() {
+ return restTemplate.getAccessToken().getValue();
+ }
+
+}
24 common/src/main/java/org/cloudfoundry/identity/uaa/client/PreAuthenticatedPrincipalSource.java
View
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package org.cloudfoundry.identity.uaa.client;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public interface PreAuthenticatedPrincipalSource<T> {
+
+ T getPrincipal();
+
+}
35 .../identity/uaa/social/SocialClientUserDetails.java → .../identity/uaa/client/SocialClientUserDetails.java
View
@@ -10,12 +10,12 @@
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.social;
+package org.cloudfoundry.identity.uaa.client;
import java.util.Collection;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.User;
/**
* Customized {@code UserDetails} implementation.
@@ -23,7 +23,7 @@
* @author Luke Taylor
* @author Dave Syer
*/
-public class SocialClientUserDetails extends User {
+public class SocialClientUserDetails extends AbstractAuthenticationToken {
public static class Source {
@@ -69,6 +69,8 @@ else if (userInfoUrl.contains("linkedin.com")) {
}
}
+ private String username;
+
private String email;
private String name;
@@ -78,7 +80,9 @@ else if (userInfoUrl.contains("linkedin.com")) {
private String source;
public SocialClientUserDetails(String username, Collection<? extends GrantedAuthority> authorities) {
- super(username, "unused", authorities);
+ super(authorities);
+ setAuthenticated(authorities!=null && !authorities.isEmpty());
+ this.username = username;
}
public String getEmail() {
@@ -98,12 +102,17 @@ public void setEmail(String email) {
}
public String getName() {
- return name;
+ // This is used as the principal name (which could then be used to look up tokens etc)
+ return username;
}
- public void setName(String name) {
+ public void setFullName(String name) {
this.name = name;
}
+
+ public String getFullName() {
+ return this.name;
+ }
public String getSource() {
return source;
@@ -112,4 +121,18 @@ public String getSource() {
public void setSource(String source) {
this.source = source;
}
+
+ public String getUsername() {
+ return username;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return "N/A";
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return this.username;
+ }
}
14 ...ity/uaa/social/SocialClientUserDetailsSource.java → ...ity/uaa/client/SocialClientUserDetailsSource.java
View
@@ -11,14 +11,15 @@
* subcomponent's license, as noted in the LICENSE file.
*/
-package org.cloudfoundry.identity.uaa.social;
+package org.cloudfoundry.identity.uaa.client;
import java.util.List;
import java.util.Map;
-import org.cloudfoundry.identity.uaa.social.SocialClientUserDetails.Source;
+import org.cloudfoundry.identity.uaa.client.SocialClientUserDetails.Source;
import org.cloudfoundry.identity.uaa.user.UaaAuthority;
import org.springframework.beans.factory.InitializingBean;
+import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.util.Assert;
import org.springframework.web.client.RestOperations;
@@ -41,7 +42,7 @@
* @author Dave Syer
*
*/
-public class SocialClientUserDetailsSource implements InitializingBean {
+public class SocialClientUserDetailsSource implements InitializingBean, PreAuthenticatedPrincipalSource<Authentication> {
private RestOperations restTemplate;
@@ -73,7 +74,7 @@ public void afterPropertiesSet() {
Assert.state(userInfoUrl != null, "User info URL must be provided");
Assert.state(restTemplate != null, "RestTemplate URL must be provided");
}
-
+
/**
* Get as much generic information as possible about the current user from the remote endpoint. The aim is to
* collect as much of the properties of a {@link SocialClientUserDetails} as possible but not to fail if there is an
@@ -82,7 +83,8 @@ public void afterPropertiesSet() {
*
* @return some user details
*/
- public SocialClientUserDetails getUserDetails() {
+ @Override
+ public Authentication getPrincipal() {
@SuppressWarnings("unchecked")
Map<String, String> map = restTemplate.getForObject(userInfoUrl, Map.class);
String userName = getUserName(map);
@@ -102,7 +104,7 @@ public SocialClientUserDetails getUserDetails() {
user.setExternalId(getUserId(map));
String fullName = getFullName(map);
if (fullName != null) {
- user.setName(fullName);
+ user.setFullName(fullName);
}
if (email != null) {
user.setEmail(email);
12 common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlMapFactoryBean.java
View
@@ -30,6 +30,7 @@
* bar:
* one: two
* three: four
+ *
* <pre>
*
* plus (later in the list)
@@ -39,6 +40,7 @@
* bar:
* one: 2
* five: six
+ *
* <pre>
*
* results in an effecive input of
@@ -49,6 +51,7 @@
* one: 2
* three: four
* five: six
+ *
* <pre>
*
* Note that the value of "foo" in the first document is not simply replaced with the value in the second, but it's nested values are merged.
@@ -58,8 +61,17 @@
*/
public class YamlMapFactoryBean extends YamlProcessor implements FactoryBean<Map<String, Object>> {
+ private Map<String, Object> instance;
+
@Override
public Map<String, Object> getObject() {
+ if (instance==null) {
+ instance = doGetObject();
+ }
+ return instance;
+ }
+
+ private Map<String, Object> doGetObject() {
final Map<String, Object> result = new LinkedHashMap<String, Object>();
MatchCallback callback = new MatchCallback() {
@Override
1  common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlProcessor.java
View
@@ -98,6 +98,7 @@ public void setMatchDefault(boolean matchDefault) {
* decide which map entries to keep in the final output from this factory. Possible values:
* <ul>
* <li><code>OVERRIDE</code> for replacing values from earlier in the list</li>
+ * <li><code>OVERRIDE_AND_IGNORE</code> the same, but ignore IO errors loading individual resources</li>
* <li><code>FIRST_FOUND</code> if you want to take the first resource in the list that exists and use just that.</li>
* </ul>
*
9 common/src/main/java/org/cloudfoundry/identity/uaa/config/YamlPropertiesFactoryBean.java
View
@@ -64,8 +64,17 @@
*/
public class YamlPropertiesFactoryBean extends YamlProcessor implements FactoryBean<Properties> {
+ private Properties instance;
+
@Override
public Properties getObject() {
+ if (instance==null) {
+ instance = doGetObject();
+ }
+ return instance;
+ }
+
+ private Properties doGetObject() {
final Properties result = new Properties();
MatchCallback callback = new MatchCallback() {
@Override
59 common/src/main/java/org/cloudfoundry/identity/uaa/event/listener/AuditListener.java
View
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-package org.cloudfoundry.identity.uaa.event.listener;
-
-import org.cloudfoundry.identity.uaa.audit.LoggingAuditService;
-import org.cloudfoundry.identity.uaa.audit.UaaAuditService;
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
-import org.cloudfoundry.identity.uaa.event.AbstractUaaEvent;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.util.Assert;
-
-/**
- * Spring {@code ApplicationListener} which picks up the listens for {@code AbstractUaaEvent}s and
- * passes the relevant information to the {@code UaaAuditService}.
- *
- * @author Luke Taylor
- */
-public class AuditListener implements ApplicationListener<ApplicationEvent> {
- private final UaaAuditService uaaAuditService;
-
- public AuditListener() {
- uaaAuditService = new LoggingAuditService();
- }
-
- public AuditListener(UaaAuditService auditor) {