1
0
mirror of synced 2026-07-09 04:40:13 +00:00

Compare commits

..

150 Commits

Author SHA1 Message Date
Spring Buildmaster f154c7d9dc Release version 4.2.12.RELEASE 2019-04-02 18:58:47 +00:00
Joe Grandja fbac953f10 Revert "Release 4.2.12.RELEASE"
This reverts commit 504c28ec01.
2019-04-02 14:14:51 -04:00
Joe Grandja 504c28ec01 Release 4.2.12.RELEASE 2019-04-02 13:24:45 -04:00
Joe Grandja 613464cda0 Update to Spring Data Ingalls-SR20
Fixes gh-6718
2019-04-02 13:04:12 -04:00
Josh Cummings 6f02f690ac Align Code with Javadoc
Fixes: gh-6734
2019-04-02 09:36:46 -06:00
Joe Grandja 14c4ac75ec Update to Spring 4.3.23
Fixes gh-6716
2019-04-01 10:49:02 -04:00
Rob Winch b46f5f69ac Manual URL Cleanup 2019-03-29 12:12:29 -04:00
Joe Grandja 28afc38c8f Update to Spring Boot 1.5.19
Fixes gh-6715
2019-03-27 15:27:07 -04:00
Joe Grandja 9f19541484 Update to bouncycastle:bcpkix-jdk15on 1.61
Fixes gh-6714
2019-03-27 14:56:16 -04:00
Joe Grandja df075a8c7c Update to aspectj 1.8.14
Fixes gh-6713
2019-03-27 14:52:19 -04:00
Joe Grandja ff24cd0b8c Update to commons-codec 1.12
Fixes gh-6712
2019-03-27 14:23:20 -04:00
Spring Operator ac93f108d6 URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

These URLs were unable to be fixed. Please review them to see if they can be manually resolved.

* [ ] http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html (200) with 1 occurrences could not be migrated:
   ([https](https://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html) result ClosedChannelException).
* [ ] http://bouncy-castle.1462172.n4.nabble.com/Java-Bouncy-Castle-scrypt-implementation-td4656832.html (200) with 1 occurrences could not be migrated:
   ([https](https://bouncy-castle.1462172.n4.nabble.com/Java-Bouncy-Castle-scrypt-implementation-td4656832.html) result SSLHandshakeException).
* [ ] http://cujojs.com/ (200) with 1 occurrences could not be migrated:
   ([https](https://cujojs.com/) result SSLHandshakeException).
* [ ] http://erik.eae.net/archives/2007/07/27/18.54.15/ (200) with 1 occurrences could not be migrated:
   ([https](https://erik.eae.net/archives/2007/07/27/18.54.15/) result SSLHandshakeException).
* [ ] http://javascript.nwbox.com/IEContentLoaded/ (200) with 1 occurrences could not be migrated:
   ([https](https://javascript.nwbox.com/IEContentLoaded/) result SSLHandshakeException).
* [ ] http://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html (200) with 1 occurrences could not be migrated:
   ([https](https://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html) result SSLHandshakeException).
* [ ] http://monkeymachine.co.uk/ (200) with 2 occurrences could not be migrated:
   ([https](https://monkeymachine.co.uk/) result SSLHandshakeException).
* [ ] http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ (200) with 1 occurrences could not be migrated:
   ([https](https://perfectionkills.com/detecting-event-support-without-browser-sniffing/) result SSLHandshakeException).
* [ ] http://somesite.com/login (200) with 3 occurrences could not be migrated:
   ([https](https://somesite.com/login) result AnnotatedConnectException).
* [ ] http://someurl.com/ (200) with 2 occurrences could not be migrated:
   ([https](https://someurl.com/) result SSLHandshakeException).
* [ ] http://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf (200) with 1 occurrences could not be migrated:
   ([https](https://webblaze.cs.berkeley.edu/papers/barth-caballero-song.pdf) result 404).
* [ ] http://www.example.com:80/ (200) with 1 occurrences could not be migrated:
   ([https](https://www.example.com:80/) result NotSslRecordException).
* [ ] http://www.faqs.org/qa/rfcc-1940.html (200) with 3 occurrences could not be migrated:
   ([https](https://www.faqs.org/qa/rfcc-1940.html) result AnnotatedConnectException).
* [ ] http://www.faqs.org/rfcs/rfc1945.html (200) with 2 occurrences could not be migrated:
   ([https](https://www.faqs.org/rfcs/rfc1945.html) result AnnotatedConnectException).
* [ ] http://www.faqs.org/rfcs/rfc3548.html (200) with 3 occurrences could not be migrated:
   ([https](https://www.faqs.org/rfcs/rfc3548.html) result AnnotatedConnectException).
* [ ] http://www.jasypt.org/springsecurity.html (200) with 1 occurrences could not be migrated:
   ([https](https://www.jasypt.org/springsecurity.html) result AnnotatedConnectException).
* [ ] http://www.zytrax.com/books/ldap/ (200) with 2 occurrences could not be migrated:
   ([https](https://www.zytrax.com/books/ldap/) result AnnotatedConnectException).
* [ ] http://blindsignals.com/index.php/2009/07/jquery-delay/ (301) with 1 occurrences could not be migrated:
   ([https](https://blindsignals.com/index.php/2009/07/jquery-delay/) result SSLHandshakeException).
* [ ] http://www.faqs.org/ (301) with 1 occurrences could not be migrated:
   ([https](https://www.faqs.org/) result AnnotatedConnectException).
* [ ] http://sam.zoy.org/wtfpl/ (301) with 2 occurrences could not be migrated:
   ([https](https://sam.zoy.org/wtfpl/) result SSLHandshakeException).
* [ ] http://hey.openid.com/ (302) with 1 occurrences could not be migrated:
   ([https](https://hey.openid.com/) result SSLHandshakeException).
* [ ] http://iharder.net/base64 (303) with 2 occurrences could not be migrated:
   ([https](https://iharder.net/base64) result AnnotatedConnectException).
* [ ] http://jaspan.com/improved_persistent_login_cookie_best_practice (500) with 3 occurrences could not be migrated:
   ([https](https://jaspan.com/improved_persistent_login_cookie_best_practice) result AnnotatedConnectException).

These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request or http redirected to an https URL, so they were migrated. Your review is recommended.

* [ ] http://www.relaxng.org/ (301) with 1 occurrences migrated to:
  https://relaxng.org/ ([https](https://www.relaxng.org/) result SSLHandshakeException).
* [ ] http://www.relaxng.org (301) with 1 occurrences migrated to:
  https://relaxng.org/ ([https](https://www.relaxng.org) result SSLHandshakeException).
* [ ] http://tools.ietf.org/html/draft-ietf-websec-x-frame-options (301) with 2 occurrences migrated to:
  https://tools.ietf.org/html/draft-ietf-websec-x-frame-options ([https](https://tools.ietf.org/html/draft-ietf-websec-x-frame-options) result ReadTimeoutException).
* [ ] http://foo.test.com (302) with 2 occurrences migrated to:
  https://www.test.com ([https](https://foo.test.com) result SSLHandshakeException).
* [ ] http://abc.test.com (302) with 2 occurrences migrated to:
  https://www.test.com ([https](https://abc.test.com) result SSLHandshakeException).
* [ ] http://192.168.1:8080 (ConnectTimeoutException) with 2 occurrences migrated to:
  https://192.168.1:8080 ([https](https://192.168.1:8080) result ConnectTimeoutException).
* [ ] http://www.example.com:8080/mycontext/secure/page.html (ConnectTimeoutException) with 1 occurrences migrated to:
  https://www.example.com:8080/mycontext/secure/page.html ([https](https://www.example.com:8080/mycontext/secure/page.html) result ConnectTimeoutException).
* [ ] http://www.example.com:8888/bigWebApp/hello (ConnectTimeoutException) with 1 occurrences migrated to:
  https://www.example.com:8888/bigWebApp/hello ([https](https://www.example.com:8888/bigWebApp/hello) result ConnectTimeoutException).
* [ ] http://www.example.com:8888/bigWebApp/hello/pathInfo.html?open=true (ConnectTimeoutException) with 1 occurrences migrated to:
  https://www.example.com:8888/bigWebApp/hello/pathInfo.html?open=true ([https](https://www.example.com:8888/bigWebApp/hello/pathInfo.html?open=true) result ConnectTimeoutException).
* [ ] http://www.opensymphony.com/sitemesh/decorator (ConnectTimeoutException) with 1 occurrences migrated to:
  https://www.opensymphony.com/sitemesh/decorator ([https](https://www.opensymphony.com/sitemesh/decorator) result ConnectTimeoutException).
* [ ] http://www.opensymphony.com/sitemesh/page (ConnectTimeoutException) with 1 occurrences migrated to:
  https://www.opensymphony.com/sitemesh/page ([https](https://www.opensymphony.com/sitemesh/page) result ConnectTimeoutException).
* [ ] http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd (ReadTimeoutException) with 1 occurrences migrated to:
  https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd ([https](https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd) result ReadTimeoutException).
* [ ] http://axschema.org/ (UnknownHostException) with 2 occurrences migrated to:
  https://axschema.org/ ([https](https://axschema.org/) result UnknownHostException).
* [ ] http://axschema.org/contact/email (UnknownHostException) with 17 occurrences migrated to:
  https://axschema.org/contact/email ([https](https://axschema.org/contact/email) result UnknownHostException).
* [ ] http://axschema.org/namePerson (UnknownHostException) with 5 occurrences migrated to:
  https://axschema.org/namePerson ([https](https://axschema.org/namePerson) result UnknownHostException).
* [ ] http://axschema.org/namePerson/first (UnknownHostException) with 4 occurrences migrated to:
  https://axschema.org/namePerson/first ([https](https://axschema.org/namePerson/first) result UnknownHostException).
* [ ] http://axschema.org/namePerson/last (UnknownHostException) with 4 occurrences migrated to:
  https://axschema.org/namePerson/last ([https](https://axschema.org/namePerson/last) result UnknownHostException).
* [ ] http://context.blah.com/context/remainder (UnknownHostException) with 1 occurrences migrated to:
  https://context.blah.com/context/remainder ([https](https://context.blah.com/context/remainder) result UnknownHostException).
* [ ] http://host/myapp/index.html;jsessionid=blah (UnknownHostException) with 1 occurrences migrated to:
  https://host/myapp/index.html;jsessionid=blah ([https](https://host/myapp/index.html;jsessionid=blah) result UnknownHostException).
* [ ] http://http://context.blah.com/context/remainder (UnknownHostException) with 1 occurrences migrated to:
  https://http://context.blah.com/context/remainder ([https](https://https://context.blah.com/context/remainder) result UnknownHostException).
* [ ] http://id.openid.zz (UnknownHostException) with 2 occurrences migrated to:
  https://id.openid.zz ([https](https://id.openid.zz) result UnknownHostException).
* [ ] http://jimi.hendrix.myopenid.com/ (UnknownHostException) with 1 occurrences migrated to:
  https://jimi.hendrix.myopenid.com/ ([https](https://jimi.hendrix.myopenid.com/) result UnknownHostException).
* [ ] http://joe.myopenid.com/ (UnknownHostException) with 3 occurrences migrated to:
  https://joe.myopenid.com/ ([https](https://joe.myopenid.com/) result UnknownHostException).
* [ ] http://openid.aol.com/ (UnknownHostException) with 2 occurrences migrated to:
  https://openid.aol.com/ ([https](https://openid.aol.com/) result UnknownHostException).
* [ ] http://pip.verisignlabs.com/server (UnknownHostException) with 2 occurrences migrated to:
  https://pip.verisignlabs.com/server ([https](https://pip.verisignlabs.com/server) result UnknownHostException).
* [ ] http://schema.openid.net/contact/email (UnknownHostException) with 6 occurrences migrated to:
  https://schema.openid.net/contact/email ([https](https://schema.openid.net/contact/email) result UnknownHostException).
* [ ] http://schema.openid.net/namePerson (UnknownHostException) with 2 occurrences migrated to:
  https://schema.openid.net/namePerson ([https](https://schema.openid.net/namePerson) result UnknownHostException).
* [ ] http://schema.openid.net/namePerson/friendly (UnknownHostException) with 2 occurrences migrated to:
  https://schema.openid.net/namePerson/friendly ([https](https://schema.openid.net/namePerson/friendly) result UnknownHostException).
* [ ] http://some.site.org/index.html (UnknownHostException) with 1 occurrences migrated to:
  https://some.site.org/index.html ([https](https://some.site.org/index.html) result UnknownHostException).
* [ ] http://specs.openid.net/auth/2.0 (UnknownHostException) with 2 occurrences migrated to:
  https://specs.openid.net/auth/2.0 ([https](https://specs.openid.net/auth/2.0) result UnknownHostException).
* [ ] http://specs.openid.net/auth/2.0/identifier_select (UnknownHostException) with 4 occurrences migrated to:
  https://specs.openid.net/auth/2.0/identifier_select ([https](https://specs.openid.net/auth/2.0/identifier_select) result UnknownHostException).
* [ ] http://wiki.fasterxml.com/JacksonFeatureModules (UnknownHostException) with 1 occurrences migrated to:
  https://wiki.fasterxml.com/JacksonFeatureModules ([https](https://wiki.fasterxml.com/JacksonFeatureModules) result UnknownHostException).
* [ ] http://www.faqs (UnknownHostException) with 1 occurrences migrated to:
  https://www.faqs ([https](https://www.faqs) result UnknownHostException).
* [ ] http://www.test123.com (UnknownHostException) with 1 occurrences migrated to:
  https://www.test123.com ([https](https://www.test123.com) result UnknownHostException).
* [ ] http://en.wikipedia.org/wiki/Defense_in_depth_%28computing%29 (301) with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Defense_in_depth_%2528computing%2529 ([https](https://en.wikipedia.org/wiki/Defense_in_depth_%28computing%29) result 400).
* [ ] http://book.git-scm.com/4_interactive_rebasing.html (301) with 1 occurrences migrated to:
  https://book.git-scm.com/4_interactive_rebasing.html ([https](https://book.git-scm.com/4_interactive_rebasing.html) result 404).
* [ ] http://docs.spring.io/spring-security/site/docs/current/apidocs/ (301) with 2 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/current/apidocs/ ([https](https://docs.spring.io/spring-security/site/docs/current/apidocs/) result 404).
* [ ] http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html (404) with 1 occurrences migrated to:
  https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html ([https](https://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/ForwardedRequestCustomizer.html) result 404).
* [ ] http://example.com/path?a=b&c=d (404) with 1 occurrences migrated to:
  https://example.com/path?a=b&c=d ([https](https://example.com/path?a=b&c=d) result 404).
* [ ] http://example.com/pkp-report (404) with 5 occurrences migrated to:
  https://example.com/pkp-report ([https](https://example.com/pkp-report) result 404).
* [ ] http://example.net/pkp-report (404) with 9 occurrences migrated to:
  https://example.net/pkp-report ([https](https://example.net/pkp-report) result 404).
* [ ] http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ (301) with 1 occurrences migrated to:
  https://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ ([https](https://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/) result 404).
* [ ] http://help.github.com/send-pull-requests (404) with 1 occurrences migrated to:
  https://help.github.com/send-pull-requests ([https](https://help.github.com/send-pull-requests) result 404).
* [ ] http://html5shim.googlecode.com/svn/trunk/html5.js (404) with 6 occurrences migrated to:
  https://html5shim.googlecode.com/svn/trunk/html5.js ([https](https://html5shim.googlecode.com/svn/trunk/html5.js) result 404).
* [ ] http://json.org/json2.js (404) with 1 occurrences migrated to:
  https://json.org/json2.js ([https](https://json.org/json2.js) result 404).
* [ ] http://openid-selector.googlecode.com/svn/trunk/ (404) with 2 occurrences migrated to:
  https://openid-selector.googlecode.com/svn/trunk/ ([https](https://openid-selector.googlecode.com/svn/trunk/) result 404).
* [ ] http://relaxng.org/ns/compatibility/annotations/1.0 (301) with 5 occurrences migrated to:
  https://relaxng.org/ns/compatibility/annotations/1.0 ([https](https://relaxng.org/ns/compatibility/annotations/1.0) result 404).
* [ ] http://www.example.com/bigWebApp/hello (404) with 2 occurrences migrated to:
  https://www.example.com/bigWebApp/hello ([https](https://www.example.com/bigWebApp/hello) result 404).
* [ ] http://www.example.com/bigWebApp/hello/pathInfo.html?open=true (404) with 1 occurrences migrated to:
  https://www.example.com/bigWebApp/hello/pathInfo.html?open=true ([https](https://www.example.com/bigWebApp/hello/pathInfo.html?open=true) result 404).
* [ ] http://www.example.com/identity (404) with 1 occurrences migrated to:
  https://www.example.com/identity ([https](https://www.example.com/identity) result 404).
* [ ] http://www.example.com/login/openid (404) with 2 occurrences migrated to:
  https://www.example.com/login/openid ([https](https://www.example.com/login/openid) result 404).
* [ ] http://www.example.com/mycontext/HelloWorld (404) with 1 occurrences migrated to:
  https://www.example.com/mycontext/HelloWorld ([https](https://www.example.com/mycontext/HelloWorld) result 404).
* [ ] http://www.example.com/mycontext/HelloWorld/some/more/segments.html (404) with 1 occurrences migrated to:
  https://www.example.com/mycontext/HelloWorld/some/more/segments.html ([https](https://www.example.com/mycontext/HelloWorld/some/more/segments.html) result 404).
* [ ] http://www.example.com/mycontext/HelloWorld?foo=bar (404) with 1 occurrences migrated to:
  https://www.example.com/mycontext/HelloWorld?foo=bar ([https](https://www.example.com/mycontext/HelloWorld?foo=bar) result 404).
* [ ] http://www.example.com/mycontext/secure/page.html (404) with 3 occurrences migrated to:
  https://www.example.com/mycontext/secure/page.html ([https](https://www.example.com/mycontext/secure/page.html) result 404).
* [ ] http://www.example.com/realm (404) with 1 occurrences migrated to:
  https://www.example.com/realm ([https](https://www.example.com/realm) result 404).
* [ ] http://www.example.com/redirect (404) with 1 occurrences migrated to:
  https://www.example.com/redirect ([https](https://www.example.com/redirect) result 404).
* [ ] http://www.example.org/do/something (404) with 4 occurrences migrated to:
  https://www.example.org/do/something ([https](https://www.example.org/do/something) result 404).
* [ ] http://www.ibm.com/developerworks/tivoli/library/t-ldap-controls/ (301) with 1 occurrences migrated to:
  https://www.ibm.com/developerworks/tivoli/library/t-ldap-controls/ ([https](https://www.ibm.com/developerworks/tivoli/library/t-ldap-controls/) result 404).
* [ ] http://www.json.org/json2.js (404) with 1 occurrences migrated to:
  https://www.json.org/json2.js ([https](https://www.json.org/json2.js) result 404).
* [ ] http://www.thymeleaf.org/thymeleaf-extras-springsecurity4 (301) with 2 occurrences migrated to:
  https://www.thymeleaf.org/thymeleaf-extras-springsecurity4 ([https](https://www.thymeleaf.org/thymeleaf-extras-springsecurity4) result 404).

These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* [ ] http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html with 1 occurrences migrated to:
  https://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html ([https](https://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html) result 200).
* [ ] http://bugs.jquery.com/ticket/12282 with 1 occurrences migrated to:
  https://bugs.jquery.com/ticket/12282 ([https](https://bugs.jquery.com/ticket/12282) result 200).
* [ ] http://bugs.jquery.com/ticket/12359 with 1 occurrences migrated to:
  https://bugs.jquery.com/ticket/12359 ([https](https://bugs.jquery.com/ticket/12359) result 200).
* [ ] http://claimid.com/ with 2 occurrences migrated to:
  https://claimid.com/ ([https](https://claimid.com/) result 200).
* [ ] http://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html with 1 occurrences migrated to:
  https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html ([https](https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html) result 200).
* [ ] http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html with 26 occurrences migrated to:
  https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html ([https](https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html) result 200).
* [ ] http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html with 1 occurrences migrated to:
  https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html ([https](https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html) result 200).
* [ ] http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html with 1 occurrences migrated to:
  https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html ([https](https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html) result 200).
* [ ] http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html with 1 occurrences migrated to:
  https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html ([https](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html) result 200).
* [ ] http://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html with 1 occurrences migrated to:
  https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html ([https](https://docs.oracle.com/javase/jndi/tutorial/ldap/connect/config.html) result 200).
* [ ] http://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/ with 2 occurrences migrated to:
  https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/ ([https](https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/) result 200).
* [ ] http://docs.spring.io/spring-framework/docs/4.1.x/spring-framework-reference/htmlsingle/ with 1 occurrences migrated to:
  https://docs.spring.io/spring-framework/docs/4.1.x/spring-framework-reference/htmlsingle/ ([https](https://docs.spring.io/spring-framework/docs/4.1.x/spring-framework-reference/htmlsingle/) result 200).
* [ ] http://static.springsource.org/spring-security/site/docs/3.0.x/reference/core-services.html (301) with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/3.0.x/reference/core-services.html ([https](https://static.springsource.org/spring-security/site/docs/3.0.x/reference/core-services.html) result 200).
* [ ] http://static.springsource.org/spring-security/site/docs/3.0.x/reference/remember-me.html (301) with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/3.0.x/reference/remember-me.html ([https](https://static.springsource.org/spring-security/site/docs/3.0.x/reference/remember-me.html) result 200).
* [ ] http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html (301) with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html ([https](https://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html) result 200).
* [ ] http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/ with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/ ([https](https://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/) result 200).
* [ ] http://docs.spring.io/spring-security/site/docs/4.2.x-SNAPSHOT/apidocs/org/springframework/security/web/authentication/preauth/RequestAttributeAuthenticationFilter.html with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/4.2.x-SNAPSHOT/apidocs/org/springframework/security/web/authentication/preauth/RequestAttributeAuthenticationFilter.html ([https](https://docs.spring.io/spring-security/site/docs/4.2.x-SNAPSHOT/apidocs/org/springframework/security/web/authentication/preauth/RequestAttributeAuthenticationFilter.html) result 200).
* [ ] http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/ with 3 occurrences migrated to:
  https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/ ([https](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/) result 200).
* [ ] http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html with 2 occurrences migrated to:
  https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html ([https](https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html) result 200).
* [ ] http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html with 1 occurrences migrated to:
  https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html ([https](https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-xml.html) result 200).
* [ ] http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html (301) with 1 occurrences migrated to:
  https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html ([https](https://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html) result 200).
* [ ] http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html with 1 occurrences migrated to:
  https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html ([https](https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html) result 200).
* [ ] http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html with 1 occurrences migrated to:
  https://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html ([https](https://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/multipart/support/MultipartFilter.html) result 200).
* [ ] http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html with 3 occurrences migrated to:
  https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html ([https](https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html) result 200).
* [ ] http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/view.html with 1 occurrences migrated to:
  https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/view.html ([https](https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/view.html) result 200).
* [ ] http://en.wikipedia.org/wiki/Clickjacking with 8 occurrences migrated to:
  https://en.wikipedia.org/wiki/Clickjacking ([https](https://en.wikipedia.org/wiki/Clickjacking) result 200).
* [ ] http://en.wikipedia.org/wiki/Content_sniffing with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Content_sniffing ([https](https://en.wikipedia.org/wiki/Content_sniffing) result 200).
* [ ] http://en.wikipedia.org/wiki/Cross-site_request_forgery with 11 occurrences migrated to:
  https://en.wikipedia.org/wiki/Cross-site_request_forgery ([https](https://en.wikipedia.org/wiki/Cross-site_request_forgery) result 200).
* [ ] http://en.wikipedia.org/wiki/Cross-site_scripting with 7 occurrences migrated to:
  https://en.wikipedia.org/wiki/Cross-site_scripting ([https](https://en.wikipedia.org/wiki/Cross-site_scripting) result 200).
* [ ] http://en.wikipedia.org/wiki/Firesheep with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Firesheep ([https](https://en.wikipedia.org/wiki/Firesheep) result 200).
* [ ] http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security with 4 occurrences migrated to:
  https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security ([https](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) result 200).
* [ ] http://en.wikipedia.org/wiki/Key_strengthening with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Key_strengthening ([https](https://en.wikipedia.org/wiki/Key_strengthening) result 200).
* [ ] http://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol ([https](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol) result 200).
* [ ] http://en.wikipedia.org/wiki/Man-in-the-middle_attack with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Man-in-the-middle_attack ([https](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) result 200).
* [ ] http://en.wikipedia.org/wiki/Null_Object_pattern with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Null_Object_pattern ([https](https://en.wikipedia.org/wiki/Null_Object_pattern) result 200).
* [ ] http://en.wikipedia.org/wiki/SRV_record with 2 occurrences migrated to:
  https://en.wikipedia.org/wiki/SRV_record ([https](https://en.wikipedia.org/wiki/SRV_record) result 200).
* [ ] http://en.wikipedia.org/wiki/Same-origin_policy with 1 occurrences migrated to:
  https://en.wikipedia.org/wiki/Same-origin_policy ([https](https://en.wikipedia.org/wiki/Same-origin_policy) result 200).
* [ ] http://en.wikipedia.org/wiki/Session_fixation with 6 occurrences migrated to:
  https://en.wikipedia.org/wiki/Session_fixation ([https](https://en.wikipedia.org/wiki/Session_fixation) result 200).
* [ ] http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice with 2 occurrences migrated to:
  https://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice ([https](https://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice) result 200).
* [ ] http://flywaydb.org/ with 1 occurrences migrated to:
  https://flywaydb.org/ ([https](https://flywaydb.org/) result 200).
* [ ] http://gradle.org with 1 occurrences migrated to:
  https://gradle.org ([https](https://gradle.org) result 200).
* [ ] http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/ with 1 occurrences migrated to:
  https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/ ([https](https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/) result 200).
* [ ] http://jquery.com/ with 1 occurrences migrated to:
  https://jquery.com/ ([https](https://jquery.com/) result 200).
* [ ] http://knockoutjs.com/ with 1 occurrences migrated to:
  https://knockoutjs.com/ ([https](https://knockoutjs.com/) result 200).
* [ ] http://marketplace.eclipse.org/content/anyedit-tools with 1 occurrences migrated to:
  https://marketplace.eclipse.org/content/anyedit-tools ([https](https://marketplace.eclipse.org/content/anyedit-tools) result 200).
* [ ] http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html with 4 occurrences migrated to:
  https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ([https](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html) result 200).
* [ ] http://openid.net with 1 occurrences migrated to:
  https://openid.net ([https](https://openid.net) result 200).
* [ ] http://openid.net/ with 1 occurrences migrated to:
  https://openid.net/ ([https](https://openid.net/) result 200).
* [ ] http://openid.net/specs/openid-attribute-exchange-1_0.html with 3 occurrences migrated to:
  https://openid.net/specs/openid-attribute-exchange-1_0.html ([https](https://openid.net/specs/openid-attribute-exchange-1_0.html) result 200).
* [ ] http://sizzlejs.com/ with 2 occurrences migrated to:
  https://sizzlejs.com/ ([https](https://sizzlejs.com/) result 200).
* [ ] http://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time with 1 occurrences migrated to:
  https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time ([https](https://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time) result 200).
* [ ] http://blog.springsource.com/2010/03/06/behind-the-spring-security-namespace/ (301) with 1 occurrences migrated to:
  https://spring.io/blog/2010/03/06/behind-the-spring-security-namespace/ ([https](https://blog.springsource.com/2010/03/06/behind-the-spring-security-namespace/) result 200).
* [ ] http://blog.springsource.com/2010/08/02/spring-security-in-google-app-engine/ (301) with 1 occurrences migrated to:
  https://spring.io/blog/2010/08/02/spring-security-in-google-app-engine/ ([https](https://blog.springsource.com/2010/08/02/spring-security-in-google-app-engine/) result 200).
* [ ] http://spring.io/projects with 1 occurrences migrated to:
  https://spring.io/projects ([https](https://spring.io/projects) result 200).
* [ ] http://spring.io/questions with 2 occurrences migrated to:
  https://spring.io/questions ([https](https://spring.io/questions) result 200).
* [ ] http://spring.io/services with 1 occurrences migrated to:
  https://spring.io/services ([https](https://spring.io/services) result 200).
* [ ] http://stackoverflow.com/questions/tagged/spring-security with 1 occurrences migrated to:
  https://stackoverflow.com/questions/tagged/spring-security ([https](https://stackoverflow.com/questions/tagged/spring-security) result 200).
* [ ] http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html with 2 occurrences migrated to:
  https://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html ([https](https://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html) result 200).
* [ ] http://tools.ietf.org/html/rfc6797 with 11 occurrences migrated to:
  https://tools.ietf.org/html/rfc6797 ([https](https://tools.ietf.org/html/rfc6797) result 200).
* [ ] http://tools.ietf.org/html/rfc7469 with 18 occurrences migrated to:
  https://tools.ietf.org/html/rfc7469 ([https](https://tools.ietf.org/html/rfc7469) result 200).
* [ ] http://vimeo.com/34436402 with 1 occurrences migrated to:
  https://vimeo.com/34436402 ([https](https://vimeo.com/34436402) result 200).
* [ ] http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/ with 1 occurrences migrated to:
  https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/ ([https](https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/) result 200).
* [ ] http://www.ja-sig.org/cas (301) with 1 occurrences migrated to:
  https://www.apereo.org ([https](https://www.ja-sig.org/cas) result 200).
* [ ] http://ehcache.sourceforge.net (301) with 2 occurrences migrated to:
  https://www.ehcache.org/ ([https](https://ehcache.sourceforge.net) result 200).
* [ ] http://www.html5rocks.com/en/tutorials/security/content-security-policy/ with 1 occurrences migrated to:
  https://www.html5rocks.com/en/tutorials/security/content-security-policy/ ([https](https://www.html5rocks.com/en/tutorials/security/content-security-policy/) result 200).
* [ ] http://www.ietf.org/rfc/rfc2396.txt with 3 occurrences migrated to:
  https://www.ietf.org/rfc/rfc2396.txt ([https](https://www.ietf.org/rfc/rfc2396.txt) result 200).
* [ ] http://www.ietf.org/rfc/rfc2617.txt with 1 occurrences migrated to:
  https://www.ietf.org/rfc/rfc2617.txt ([https](https://www.ietf.org/rfc/rfc2617.txt) result 200).
* [ ] http://www.liquibase.org/ with 1 occurrences migrated to:
  https://www.liquibase.org/ ([https](https://www.liquibase.org/) result 200).
* [ ] http://www.openbsd.org/papers/bcrypt-paper.ps with 1 occurrences migrated to:
  https://www.openbsd.org/papers/bcrypt-paper.ps ([https](https://www.openbsd.org/papers/bcrypt-paper.ps) result 200).
* [ ] http://www.springframework.org/schema/aop/spring-aop-2.5.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/aop/spring-aop-2.5.xsd ([https](https://www.springframework.org/schema/aop/spring-aop-2.5.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-2.5.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-2.5.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-2.5.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-3.0.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-3.0.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans.xsd ([https](https://www.springframework.org/schema/beans/spring-beans.xsd) result 200).
* [ ] http://www.springframework.org/schema/context/spring-context-2.5.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context-2.5.xsd ([https](https://www.springframework.org/schema/context/spring-context-2.5.xsd) result 200).
* [ ] http://www.springframework.org/schema/mvc/spring-mvc.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/mvc/spring-mvc.xsd ([https](https://www.springframework.org/schema/mvc/spring-mvc.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security.xsd with 3 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security.xsd ([https](https://www.springframework.org/schema/security/spring-security.xsd) result 200).
* [ ] http://www.springframework.org/schema/websocket/spring-websocket.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/websocket/spring-websocket.xsd ([https](https://www.springframework.org/schema/websocket/spring-websocket.xsd) result 200).
* [ ] http://www.test.com with 9 occurrences migrated to:
  https://www.test.com ([https](https://www.test.com) result 200).
* [ ] http://www.thymeleaf.org with 19 occurrences migrated to:
  https://www.thymeleaf.org ([https](https://www.thymeleaf.org) result 200).
* [ ] http://www.thymeleaf.org/ with 3 occurrences migrated to:
  https://www.thymeleaf.org/ ([https](https://www.thymeleaf.org/) result 200).
* [ ] http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd with 1 occurrences migrated to:
  https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd ([https](https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd) result 200).
* [ ] http://www.thymeleaf.org/whatsnew21.html with 1 occurrences migrated to:
  https://www.thymeleaf.org/whatsnew21.html ([https](https://www.thymeleaf.org/whatsnew21.html) result 200).
* [ ] http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html with 2 occurrences migrated to:
  https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html ([https](https://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html) result 200).
* [ ] http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html with 1 occurrences migrated to:
  https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html ([https](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) result 200).
* [ ] http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html with 1 occurrences migrated to:
  https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html ([https](https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html) result 200).
* [ ] http://www.w3.org/TR/2011/REC-css3-selectors-20110929/ with 2 occurrences migrated to:
  https://www.w3.org/TR/2011/REC-css3-selectors-20110929/ ([https](https://www.w3.org/TR/2011/REC-css3-selectors-20110929/) result 200).
* [ ] http://www.w3.org/TR/CSS21/syndata.html with 1 occurrences migrated to:
  https://www.w3.org/TR/CSS21/syndata.html ([https](https://www.w3.org/TR/CSS21/syndata.html) result 200).
* [ ] http://www.w3.org/TR/selectors/ with 3 occurrences migrated to:
  https://www.w3.org/TR/selectors/ ([https](https://www.w3.org/TR/selectors/) result 200).
* [ ] http://www.youtube.com/watch?v=3mk0RySeNsU with 1 occurrences migrated to:
  https://www.youtube.com/watch?v=3mk0RySeNsU ([https](https://www.youtube.com/watch?v=3mk0RySeNsU) result 200).
* [ ] http://api.jquery.com/jQuery.browser with 1 occurrences migrated to:
  https://api.jquery.com/jQuery.browser ([https](https://api.jquery.com/jQuery.browser) result 301).
* [ ] http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx with 1 occurrences migrated to:
  https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx ([https](https://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx) result 301).
* [ ] http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx with 2 occurrences migrated to:
  https://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx ([https](https://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx) result 301).
* [ ] http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx with 2 occurrences migrated to:
  https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx ([https](https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx) result 301).
* [ ] http://code.google.com/p/openid-selector/ with 3 occurrences migrated to:
  https://code.google.com/p/openid-selector/ ([https](https://code.google.com/p/openid-selector/) result 301).
* [ ] http://contributor-covenant.org with 1 occurrences migrated to:
  https://contributor-covenant.org ([https](https://contributor-covenant.org) result 301).
* [ ] http://contributor-covenant.org/version/1/3/0/ with 1 occurrences migrated to:
  https://contributor-covenant.org/version/1/3/0/ ([https](https://contributor-covenant.org/version/1/3/0/) result 301).
* [ ] http://dev.w3.org/csswg/cssom/ with 1 occurrences migrated to:
  https://dev.w3.org/csswg/cssom/ ([https](https://dev.w3.org/csswg/cssom/) result 301).
* [ ] http://docs.spring.io with 1 occurrences migrated to:
  https://docs.spring.io ([https](https://docs.spring.io) result 301).
* [ ] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html with 1 occurrences migrated to:
  https://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html ([https](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html) result 301).
* [ ] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html with 7 occurrences migrated to:
  https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html ([https](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html) result 301).
* [ ] http://forum.springsource.org/showthread.php?102783-How-to-use-hasIpAddress&p=343971 (301) with 1 occurrences migrated to:
  https://forum.spring.io/showthread.php?102783-How-to-use-hasIpAddress&p=343971 ([https](https://forum.springsource.org/showthread.php?102783-How-to-use-hasIpAddress&p=343971) result 301).
* [ ] http://help.github.com/set-up-git-redirect with 1 occurrences migrated to:
  https://help.github.com/set-up-git-redirect ([https](https://help.github.com/set-up-git-redirect) result 301).
* [ ] http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_ with 1 occurrences migrated to:
  https://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_ ([https](https://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_) result 301).
* [ ] http://jquery.org/license with 1 occurrences migrated to:
  https://jquery.org/license ([https](https://jquery.org/license) result 301).
* [ ] http://msdn.microsoft.com/en-us/library/dd565647 with 4 occurrences migrated to:
  https://msdn.microsoft.com/en-us/library/dd565647 ([https](https://msdn.microsoft.com/en-us/library/dd565647) result 301).
* [ ] http://msdn.microsoft.com/en-us/library/ie/gg622941 with 5 occurrences migrated to:
  https://msdn.microsoft.com/en-us/library/ie/gg622941 ([https](https://msdn.microsoft.com/en-us/library/ie/gg622941) result 301).
* [ ] http://openid.net/get/ with 2 occurrences migrated to:
  https://openid.net/get/ ([https](https://openid.net/get/) result 301).
* [ ] http://openid.net/what/ with 2 occurrences migrated to:
  https://openid.net/what/ ([https](https://openid.net/what/) result 301).
* [ ] http://technorati.com/people/technorati/ with 2 occurrences migrated to:
  https://technorati.com/people/technorati/ ([https](https://technorati.com/people/technorati/) result 301).
* [ ] http://twitter.github.com/bootstrap/javascript.html with 13 occurrences migrated to:
  https://twitter.github.com/bootstrap/javascript.html ([https](https://twitter.github.com/bootstrap/javascript.html) result 301).
* [ ] http://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html with 1 occurrences migrated to:
  https://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html ([https](https://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html) result 301).
* [ ] http://www.jasig.org/cas with 1 occurrences migrated to:
  https://www.jasig.org/cas ([https](https://www.jasig.org/cas) result 301).
* [ ] http://www.modernizr.com/ with 1 occurrences migrated to:
  https://www.modernizr.com/ ([https](https://www.modernizr.com/) result 301).
* [ ] http://www.opensource.org/licenses/mit-license.php with 1 occurrences migrated to:
  https://www.opensource.org/licenses/mit-license.php ([https](https://www.opensource.org/licenses/mit-license.php) result 301).
* [ ] http://www.oracle.com/technetwork/java/javase/downloads with 1 occurrences migrated to:
  https://www.oracle.com/technetwork/java/javase/downloads ([https](https://www.oracle.com/technetwork/java/javase/downloads) result 301).
* [ ] http://www.owasp.org/ with 1 occurrences migrated to:
  https://www.owasp.org/ ([https](https://www.owasp.org/) result 301).
* [ ] http://www.springframework.org/security with 1 occurrences migrated to:
  https://www.springframework.org/security ([https](https://www.springframework.org/security) result 301).
* [ ] http://www.springsource.com/ with 2 occurrences migrated to:
  https://www.springsource.com/ ([https](https://www.springsource.com/) result 301).
* [ ] http://www.springsource.org with 1 occurrences migrated to:
  https://www.springsource.org ([https](https://www.springsource.org) result 301).
* [ ] http://www.springsource.org/sts with 1 occurrences migrated to:
  https://www.springsource.org/sts ([https](https://www.springsource.org/sts) result 301).
* [ ] http://www.thoughtcrime.org/software/sslstrip/ with 1 occurrences migrated to:
  https://www.thoughtcrime.org/software/sslstrip/ ([https](https://www.thoughtcrime.org/software/sslstrip/) result 301).
* [ ] http://www.w3.org/TR/css3-selectors/ with 2 occurrences migrated to:
  https://www.w3.org/TR/css3-selectors/ ([https](https://www.w3.org/TR/css3-selectors/) result 301).
* [ ] http://www.w3.org/TR/css3-syntax/ with 1 occurrences migrated to:
  https://www.w3.org/TR/css3-syntax/ ([https](https://www.w3.org/TR/css3-syntax/) result 301).
* [ ] http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ with 3 occurrences migrated to:
  https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ ([https](https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/) result 302).
* [ ] http://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html with 1 occurrences migrated to:
  https://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html ([https](https://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html) result 302).
* [ ] http://flickr.com/ with 2 occurrences migrated to:
  https://flickr.com/ ([https](https://flickr.com/) result 302).
* [ ] http://git-scm.com/book/cs/ch7-3.html with 1 occurrences migrated to:
  https://git-scm.com/book/cs/ch7-3.html ([https](https://git-scm.com/book/cs/ch7-3.html) result 302).
* [ ] http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd with 1 occurrences migrated to:
  https://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd ([https](https://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html ([https](https://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/Callback.html with 4 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/Callback.html ([https](https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/Callback.html) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/CallbackHandler.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/CallbackHandler.html ([https](https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/CallbackHandler.html) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/NameCallback.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/NameCallback.html ([https](https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/NameCallback.html) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/PasswordCallback.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/PasswordCallback.html ([https](https://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/callback/PasswordCallback.html) result 302).
* [ ] http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html with 2 occurrences migrated to:
  https://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html ([https](https://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html) result 302).
* [ ] http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/callback/CallbackHandler.html with 2 occurrences migrated to:
  https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/callback/CallbackHandler.html ([https](https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/callback/CallbackHandler.html) result 302).
* [ ] http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html ([https](https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html) result 302).
* [ ] http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html with 2 occurrences migrated to:
  https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html ([https](https://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html) result 302).
* [ ] http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html with 1 occurrences migrated to:
  https://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html ([https](https://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html) result 302).
* [ ] http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html with 3 occurrences migrated to:
  https://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html ([https](https://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html) result 302).
* [ ] http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd with 1 occurrences migrated to:
  https://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd ([https](https://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd) result 302).
* [ ] http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd with 1 occurrences migrated to:
  https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd ([https](https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd) result 302).
* [ ] http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd with 2 occurrences migrated to:
  https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd ([https](https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd) result 302).
* [ ] http://msdn.microsoft.com/en-us/library/ms680857%28VS.85%29.aspx with 1 occurrences migrated to:
  https://msdn.microsoft.com/en-us/library/ms680857%28VS.85%29.aspx ([https](https://msdn.microsoft.com/en-us/library/ms680857%28VS.85%29.aspx) result 302).
* [ ] http://repo.spring.io/milestone with 1 occurrences migrated to:
  https://repo.spring.io/milestone ([https](https://repo.spring.io/milestone) result 302).
* [ ] http://repo.spring.io/snapshot with 1 occurrences migrated to:
  https://repo.spring.io/snapshot ([https](https://repo.spring.io/snapshot) result 302).
* [ ] http://spring.io/spring-security with 3 occurrences migrated to:
  https://spring.io/spring-security ([https](https://spring.io/spring-security) result 302).
* [ ] http://spring.io/spring-security/ with 2 occurrences migrated to:
  https://spring.io/spring-security/ ([https](https://spring.io/spring-security/) result 302).
* [ ] http://spring.io/tools/sts with 1 occurrences migrated to:
  https://spring.io/tools/sts ([https](https://spring.io/tools/sts) result 302).
* [ ] http://tools.ietf.org/draft/draft-behera-ldap-password-policy/draft-behera-ldap-password-policy-09.txt with 2 occurrences migrated to:
  https://tools.ietf.org/draft/draft-behera-ldap-password-policy/draft-behera-ldap-password-policy-09.txt ([https](https://tools.ietf.org/draft/draft-behera-ldap-password-policy/draft-behera-ldap-password-policy-09.txt) result 302).
* [ ] http://webauth.stanford.edu/manual/mod/mod_webauth.html with 1 occurrences migrated to:
  https://webauth.stanford.edu/manual/mod/mod_webauth.html ([https](https://webauth.stanford.edu/manual/mod/mod_webauth.html) result 302).
* [ ] http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context with 1 occurrences migrated to:
  https://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context ([https](https://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context) result 302).
* [ ] http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-authmeth-19.txt with 1 occurrences migrated to:
  https://www.ietf.org/internet-drafts/draft-ietf-ldapbis-authmeth-19.txt ([https](https://www.ietf.org/internet-drafts/draft-ietf-ldapbis-authmeth-19.txt) result 302).

These URLs were intentionally ignored.

* http://java.sun.com/JSP/Page with 14 occurrences
* http://java.sun.com/jsp/jstl/core with 31 occurrences
* http://java.sun.com/jsp/jstl/fmt with 6 occurrences
* http://java.sun.com/jsp/jstl/functions with 1 occurrences
* http://java.sun.com/jstl/core with 1 occurrences
* http://java.sun.com/jstl/core_rt with 3 occurrences
* http://java.sun.com/xml/ns/j2ee with 2 occurrences
* http://java.sun.com/xml/ns/javaee with 6 occurrences
* http://localhost with 3 occurrences
* http://localhost/ with 3 occurrences
* http://localhost/Test</value></property&gt with 1 occurrences
* http://localhost/appcontext/page with 1 occurrences
* http://localhost/authentication/login with 2 occurrences
* http://localhost/login with 21 occurrences
* http://localhost/messages with 1 occurrences
* http://localhost/some-url with 2 occurrences
* http://localhost/tosave with 1 occurrences
* http://localhost/user with 1 occurrences
* http://localhost:8080 with 1 occurrences
* http://localhost:8080/ with 4 occurrences
* http://localhost:8080/SomeService with 1 occurrences
* http://localhost:8080/contacts with 1 occurrences
* http://localhost:8080/sample/ with 15 occurrences
* http://localhost:8080/spring-security-samples-tutorial/listAccounts.html with 4 occurrences
* http://localhost:8080/spring-security-samples-tutorial/post.html?id=1 with 4 occurrences
* http://localhost:9080/user with 1 occurrences
* http://someid with 1 occurrences
* http://something/ with 1 occurrences
* http://test.com with 1 occurrences
* http://test.foobar.com with 1 occurrences
* http://testopenid.com?openid.return_to= with 2 occurrences
* http://www.springframework.org/schema/aop with 2 occurrences
* http://www.springframework.org/schema/beans with 8 occurrences
* http://www.springframework.org/schema/context with 2 occurrences
* http://www.springframework.org/schema/mvc with 2 occurrences
* http://www.springframework.org/schema/security with 36 occurrences
* http://www.springframework.org/schema/security/spring-security- with 1 occurrences
* http://www.springframework.org/schema/websocket with 2 occurrences
* http://www.springframework.org/security/tags with 22 occurrences
* http://www.springframework.org/tags with 12 occurrences
* http://www.springframework.org/tags/form with 14 occurrences
* http://www.w3.org/1999/XSL/Transform with 1 occurrences
* http://www.w3.org/1999/xhtml with 20 occurrences
* http://www.w3.org/2001/XMLSchema with 13 occurrences
* http://www.w3.org/2001/XMLSchema-datatypes with 5 occurrences
* http://www.w3.org/2001/XMLSchema-instance with 9 occurrences

Fixes gh-6658
2019-03-26 22:47:52 -04:00
Spring Operator 6653a40ddd URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

These URLs were unable to be fixed. Please review them to see if they can be manually resolved.

* [ ] http://luke.taylor.openid.cn/ (200) with 1 occurrences could not be migrated:
   ([https](https://luke.taylor.openid.cn/) result SSLHandshakeException).

These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request or http redirected to an https URL, so they were migrated. Your review is recommended.

* [ ] http://jetty.mortbay.org/configure.dtd (ConnectTimeoutException) with 1 occurrences migrated to:
  https://jetty.mortbay.org/configure.dtd ([https](https://jetty.mortbay.org/configure.dtd) result ConnectTimeoutException).
* [ ] http://axschema.org/contact/email (UnknownHostException) with 2 occurrences migrated to:
  https://axschema.org/contact/email ([https](https://axschema.org/contact/email) result UnknownHostException).
* [ ] http://axschema.org/namePerson (UnknownHostException) with 1 occurrences migrated to:
  https://axschema.org/namePerson ([https](https://axschema.org/namePerson) result UnknownHostException).
* [ ] http://axschema.org/namePerson/first (UnknownHostException) with 1 occurrences migrated to:
  https://axschema.org/namePerson/first ([https](https://axschema.org/namePerson/first) result UnknownHostException).
* [ ] http://axschema.org/namePerson/last (UnknownHostException) with 1 occurrences migrated to:
  https://axschema.org/namePerson/last ([https](https://axschema.org/namePerson/last) result UnknownHostException).
* [ ] http://luke.taylor.myopenid.com/ (UnknownHostException) with 1 occurrences migrated to:
  https://luke.taylor.myopenid.com/ ([https](https://luke.taylor.myopenid.com/) result UnknownHostException).
* [ ] http://schema.openid.net/contact/email (UnknownHostException) with 1 occurrences migrated to:
  https://schema.openid.net/contact/email ([https](https://schema.openid.net/contact/email) result UnknownHostException).
* [ ] http://schema.openid.net/namePerson (UnknownHostException) with 1 occurrences migrated to:
  https://schema.openid.net/namePerson ([https](https://schema.openid.net/namePerson) result UnknownHostException).
* [ ] http://spring.security.test.myopenid.com/ (UnknownHostException) with 1 occurrences migrated to:
  https://spring.security.test.myopenid.com/ ([https](https://spring.security.test.myopenid.com/) result UnknownHostException).
* [ ] http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng (404) with 1 occurrences migrated to:
  https://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng ([https](https://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng) result 404).
* [ ] http://www.puppycrawl.com/dtds/configuration_1_3.dtd (404) with 1 occurrences migrated to:
  https://www.puppycrawl.com/dtds/configuration_1_3.dtd ([https](https://www.puppycrawl.com/dtds/configuration_1_3.dtd) result 404).
* [ ] http://www.puppycrawl.com/dtds/suppressions_1_1.dtd (404) with 1 occurrences migrated to:
  https://www.puppycrawl.com/dtds/suppressions_1_1.dtd ([https](https://www.puppycrawl.com/dtds/suppressions_1_1.dtd) result 404).
* [ ] http://www.se-radio.net/transcript-82-organization-large-code-bases-juergen-hoeller (404) with 1 occurrences migrated to:
  https://www.se-radio.net/transcript-82-organization-large-code-bases-juergen-hoeller ([https](https://www.se-radio.net/transcript-82-organization-large-code-bases-juergen-hoeller) result 404).
* [ ] http://www.springframework.org/schema/config/spring-config-2.5.xsd (404) with 1 occurrences migrated to:
  https://www.springframework.org/schema/config/spring-config-2.5.xsd ([https](https://www.springframework.org/schema/config/spring-config-2.5.xsd) result 404).
* [ ] http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd (404) with 1 occurrences migrated to:
  https://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd ([https](https://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd) result 404).
* [ ] http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd (404) with 1 occurrences migrated to:
  https://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd ([https](https://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd) result 404).

These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* [ ] http://maven.apache.org/xsd/maven-4.0.0.xsd with 52 occurrences migrated to:
  https://maven.apache.org/xsd/maven-4.0.0.xsd ([https](https://maven.apache.org/xsd/maven-4.0.0.xsd) result 200).
* [ ] http://raykrueger.blogspot.com/ with 1 occurrences migrated to:
  https://raykrueger.blogspot.com/ ([https](https://raykrueger.blogspot.com/) result 200).
* [ ] http://www.infoq.com/presentations/code-organization-large-projects with 1 occurrences migrated to:
  https://www.infoq.com/presentations/code-organization-large-projects ([https](https://www.infoq.com/presentations/code-organization-large-projects) result 200).
* [ ] http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd with 1 occurrences migrated to:
  https://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd ([https](https://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd) result 200).
* [ ] http://www.springframework.org/dtd/spring-beans.dtd with 5 occurrences migrated to:
  https://www.springframework.org/dtd/spring-beans.dtd ([https](https://www.springframework.org/dtd/spring-beans.dtd) result 200).
* [ ] http://www.springframework.org/schema/aop/spring-aop-3.0.xsd with 7 occurrences migrated to:
  https://www.springframework.org/schema/aop/spring-aop-3.0.xsd ([https](https://www.springframework.org/schema/aop/spring-aop-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/aop/spring-aop-3.2.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/aop/spring-aop-3.2.xsd ([https](https://www.springframework.org/schema/aop/spring-aop-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/aop/spring-aop.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/aop/spring-aop.xsd ([https](https://www.springframework.org/schema/aop/spring-aop.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-3.0.xsd with 46 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-3.0.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-3.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-3.1.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-3.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-3.2.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-3.2.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans-4.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans-4.1.xsd ([https](https://www.springframework.org/schema/beans/spring-beans-4.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/beans/spring-beans.xsd with 9 occurrences migrated to:
  https://www.springframework.org/schema/beans/spring-beans.xsd ([https](https://www.springframework.org/schema/beans/spring-beans.xsd) result 200).
* [ ] http://www.springframework.org/schema/context/spring-context-3.0.xsd with 6 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context-3.0.xsd ([https](https://www.springframework.org/schema/context/spring-context-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/context/spring-context-3.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context-3.1.xsd ([https](https://www.springframework.org/schema/context/spring-context-3.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/context/spring-context-3.2.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context-3.2.xsd ([https](https://www.springframework.org/schema/context/spring-context-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/context/spring-context.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/context/spring-context.xsd ([https](https://www.springframework.org/schema/context/spring-context.xsd) result 200).
* [ ] http://www.springframework.org/schema/data/jpa/spring-jpa.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/data/jpa/spring-jpa.xsd ([https](https://www.springframework.org/schema/data/jpa/spring-jpa.xsd) result 200).
* [ ] http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd ([https](https://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd ([https](https://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd ([https](https://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security-2.0.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security-2.0.1.xsd ([https](https://www.springframework.org/schema/security/spring-security-2.0.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security-2.0.2.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security-2.0.2.xsd ([https](https://www.springframework.org/schema/security/spring-security-2.0.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security-2.0.xsd with 5 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security-2.0.xsd ([https](https://www.springframework.org/schema/security/spring-security-2.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security-3.0.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security-3.0.xsd ([https](https://www.springframework.org/schema/security/spring-security-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security-3.2.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security-3.2.xsd ([https](https://www.springframework.org/schema/security/spring-security-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/security/spring-security.xsd with 33 occurrences migrated to:
  https://www.springframework.org/schema/security/spring-security.xsd ([https](https://www.springframework.org/schema/security/spring-security.xsd) result 200).
* [ ] http://www.springframework.org/schema/tx/spring-tx-3.0.xsd with 3 occurrences migrated to:
  https://www.springframework.org/schema/tx/spring-tx-3.0.xsd ([https](https://www.springframework.org/schema/tx/spring-tx-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/tx/spring-tx-3.2.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/tx/spring-tx-3.2.xsd ([https](https://www.springframework.org/schema/tx/spring-tx-3.2.xsd) result 200).
* [ ] http://www.springframework.org/schema/tx/spring-tx.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/tx/spring-tx.xsd ([https](https://www.springframework.org/schema/tx/spring-tx.xsd) result 200).
* [ ] http://www.springframework.org/schema/util/spring-util-2.5.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/util/spring-util-2.5.xsd ([https](https://www.springframework.org/schema/util/spring-util-2.5.xsd) result 200).
* [ ] http://www.springframework.org/schema/util/spring-util-3.0.xsd with 6 occurrences migrated to:
  https://www.springframework.org/schema/util/spring-util-3.0.xsd ([https](https://www.springframework.org/schema/util/spring-util-3.0.xsd) result 200).
* [ ] http://www.springframework.org/schema/util/spring-util-3.1.xsd with 1 occurrences migrated to:
  https://www.springframework.org/schema/util/spring-util-3.1.xsd ([https](https://www.springframework.org/schema/util/spring-util-3.1.xsd) result 200).
* [ ] http://www.springframework.org/schema/util/spring-util.xsd with 2 occurrences migrated to:
  https://www.springframework.org/schema/util/spring-util.xsd ([https](https://www.springframework.org/schema/util/spring-util.xsd) result 200).
* [ ] http://www.headwaysoftware.com with 1 occurrences migrated to:
  https://www.headwaysoftware.com ([https](https://www.headwaysoftware.com) result 301).
* [ ] http://java.sun.com/dtd/web-app_2_3.dtd with 2 occurrences migrated to:
  https://java.sun.com/dtd/web-app_2_3.dtd ([https](https://java.sun.com/dtd/web-app_2_3.dtd) result 302).
* [ ] http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd with 2 occurrences migrated to:
  https://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ([https](https://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd) result 302).
* [ ] http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd with 10 occurrences migrated to:
  https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd ([https](https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd) result 302).
* [ ] http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd with 2 occurrences migrated to:
  https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd ([https](https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd) result 302).
* [ ] http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd with 1 occurrences migrated to:
  https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd ([https](https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd) result 302).

These URLs were intentionally ignored.

* http://appengine.google.com/ns/1.0 with 1 occurrences
* http://docbook.org/ns/docbook with 1 occurrences
* http://jakarta.apache.org/log4j/ with 1 occurrences
* http://java.sun.com/xml/ns/j2ee with 4 occurrences
* http://java.sun.com/xml/ns/javaee with 22 occurrences
* http://java.sun.com/xml/ns/persistence with 2 occurrences
* http://maven.apache.org/POM/4.0.0 with 104 occurrences
* http://somehost/someUrl with 1 occurrences
* http://www.springframework.org/schema/aop with 18 occurrences
* http://www.springframework.org/schema/beans with 118 occurrences
* http://www.springframework.org/schema/c with 6 occurrences
* http://www.springframework.org/schema/config with 2 occurrences
* http://www.springframework.org/schema/context with 20 occurrences
* http://www.springframework.org/schema/data/jpa with 2 occurrences
* http://www.springframework.org/schema/jdbc with 2 occurrences
* http://www.springframework.org/schema/mvc with 6 occurrences
* http://www.springframework.org/schema/p with 12 occurrences
* http://www.springframework.org/schema/security with 86 occurrences
* http://www.springframework.org/schema/tx with 14 occurrences
* http://www.springframework.org/schema/util with 20 occurrences
* http://www.springframework.org/schema/webflow with 2 occurrences
* http://www.springframework.org/schema/webflow-config with 2 occurrences
* http://www.w3.org/1999/xlink with 1 occurrences
* http://www.w3.org/2001/XMLSchema-instance with 126 occurrences

Fixes gh-6651
2019-03-26 22:30:09 -04:00
Spring Operator 70851032e4 URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

# Fixed URLs

## Fixed Success
These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended.

* http://www.apache.org/licenses/ with 1 occurrences migrated to:
  https://www.apache.org/licenses/ ([https](https://www.apache.org/licenses/) result 200).
* http://www.apache.org/licenses/LICENSE-2.0 with 1820 occurrences migrated to:
  https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200).
* http://www.apache.org/licenses/LICENSE-2.0.html with 1 occurrences migrated to:
  https://www.apache.org/licenses/LICENSE-2.0.html ([https](https://www.apache.org/licenses/LICENSE-2.0.html) result 200).
2019-03-14 20:23:19 -05:00
Rob Winch 93f99d0a66 Polish URLs
We have performed some polish on your URLs. We do not follow redirects to avoid expanding intentionally shorter URLs (i.e. URL shortened URLs)

# Fixed URLs

## Fixed But Review Recommended
These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request, so we migrated them. Your review is recommended.

| HTTP URL | Result URL | HTTPS Result | HTTP Result | Count |
| --- | --- | --- | --- | --- |
| http://repo.terracotta.org/maven2/ | https://repo.terracotta.org/maven2/ | HttpResponse(httpStatus = 403 FORBIDDEN) | HttpResponse(httpStatus = 403 FORBIDDEN) | 1 |
## Fixed Success
These URLs were fixed successfully.

| HTTP URL | Result URL | HTTPS Result | HTTP Result | Count |
| --- | --- | --- | --- | --- |
| http://docs.spring.io/spring-ldap/docs/1.3.x/apidocs/ | https://docs.spring.io/spring-ldap/docs/1.3.x/apidocs/ | HttpResponse(httpStatus = 200 OK) | null | 2 |
| http://docs.spring.io/spring/docs/3.2.x/javadoc-api | https://docs.spring.io/spring/docs/3.2.x/javadoc-api | HttpResponse(httpStatus = 301 MOVED_PERMANENTLY redirectUrl = http://docs.spring.io/spring/docs/3.2.x/javadoc-api/) | null | 1 |
| http://docs.spring.io/spring/docs/3.2.x/javadoc-api/ | https://docs.spring.io/spring/docs/3.2.x/javadoc-api/ | HttpResponse(httpStatus = 200 OK) | null | 1 |
| http://download.oracle.com/javase/6/docs/api/ | https://download.oracle.com/javase/6/docs/api/ | HttpResponse(httpStatus = 302 FOUND redirectUrl = https://docs.oracle.com/javase/6/docs/api/) | null | 2 |
| http://spring.io/ | https://spring.io/ | HttpResponse(httpStatus = 200 OK) | null | 53 |
| http://spring.io/spring-security | https://spring.io/spring-security | HttpResponse(httpStatus = 302 FOUND redirectUrl = https://projects.spring.io/spring-security) | null | 53 |
| http://www.apache.org/licenses/LICENSE-2.0.txt | https://www.apache.org/licenses/LICENSE-2.0.txt | HttpResponse(httpStatus = 200 OK) | null | 53 |
| http://forums.gradle.org/gradle/topics/after_upgrade_gradle_to_2_0_version_the_maven_pom_not_support_build_property | https://discuss.gradle.org/gradle/topics/after_upgrade_gradle_to_2_0_version_the_maven_pom_not_support_build_property | HttpResponse(httpStatus = 404 NOT_FOUND) | HttpResponse(httpStatus = 301 MOVED_PERMANENTLY redirectUrl = https://discuss.gradle.org/gradle/topics/after_upgrade_gradle_to_2_0_version_the_maven_pom_not_support_build_property) | 1 |
| http://forums.gradle.org/gradle/topics/eclipse_wtp_deploys_testcode_to_server_example_provided | https://discuss.gradle.org/gradle/topics/eclipse_wtp_deploys_testcode_to_server_example_provided | HttpResponse(httpStatus = 404 NOT_FOUND) | HttpResponse(httpStatus = 301 MOVED_PERMANENTLY redirectUrl = https://discuss.gradle.org/gradle/topics/eclipse_wtp_deploys_testcode_to_server_example_provided) | 1 |

# Ignored
These URLs were intentionally ignored so we didn't migrate them.

| HTTP URL |
| --- |
| http://maven.apache.org/POM/4.0.0 |
| http://maven.apache.org/xsd/maven-4.0.0.xsd |
| http://www.w3.org/2001/XMLSchema-instance |
2019-03-01 19:37:44 -06:00
Rob Winch 7cabf2774b Removed Unused Configuration 2019-02-28 20:11:46 -06:00
Rob Winch da17016bbd Fix CsrfBeanDefinitionParserTests Merge
Issue: gh-6423
2019-01-22 14:15:37 -06:00
Ankur Pathak 41a7d82211 Improve CsrfBeanDefinitionParser xml parsing
1. CsrfBeanDefinitionParser registers requestDataValueProcessor
if not already registered
2. Created Tests in CsrfBeanDefinitionParserTests

Fixes: gh-6423
2019-01-22 14:06:49 -06:00
Spring Buildmaster d4a3f1ee4d Next development version 2019-01-10 22:56:06 +00:00
Spring Buildmaster 64682ab6b8 [artifactory-release] 4.2.11.RELEASE 2019-01-10 22:56:01 +00:00
Joe Grandja 2484f72292 Update to ehcache 2.10.6
Fixes gh-6411
2019-01-10 16:13:19 -05:00
Joe Grandja 1693625acb Update to cglib-nodep 3.2.10
Fixes gh-6409
2019-01-10 15:48:56 -05:00
Joe Grandja 0f7645aa50 MIN_SPRING_VERSION is 4.3.22.RELEASE 2019-01-10 15:40:23 -05:00
Joe Grandja f79fe3ce46 Update to spring-boot-gradle-plugin 1.5.18
Fixes gh-6408
2019-01-10 15:38:51 -05:00
Joe Grandja 853765c55c Update to Spring Data Ingalls-SR18
Fixes gh-6407
2019-01-10 15:35:47 -05:00
Joe Grandja 59ea0f0711 Update to Spring Framework 4.3.22
Fixes gh-6406
2019-01-10 15:27:11 -05:00
Rob Winch 7da0c74095 Fix MethodSecurityEvaluationContextTests
Update for 4.2.x code base

Issue: gh-6384
2019-01-10 10:50:45 -06:00
Ankur Pathak e8d58498b0 fixes setting paramName only when it is not null
Fixes: gh-6223
2019-01-10 10:36:58 -06:00
Ankur Pathak 5802393073 Fixes typo in x,rnc files
1. Fixes type ammount to amount in *.rnc files
2. Regenerates *.xsd files from *.rnc files

Fixes: gh-6325
2019-01-08 11:34:59 -07:00
Slava Semushin bab5b73e71 LazyCsrfTokenRepository: fix a typo in javadoc. 2019-01-07 13:41:18 -06:00
Zhanwei Wang 717bf4819b Improve error message for Chinese. 2018-12-06 13:55:56 -06:00
lmagyar fd31e52fb1 SecurityContextCallableProcessingInterceptor thread visibility fix
Within class SecurityContextCallableProcessingInterceptor field securityContext should volatile.

Fixes gh-6143
2018-12-03 15:49:33 -06:00
Spring Buildmaster 4732d08080 Next development version 2018-11-28 18:49:52 +00:00
Spring Buildmaster 2c69092bdd Release version 4.2.10.RELEASE 2018-11-28 18:49:48 +00:00
Rob Winch 8f671f807c Update to Jackson 2.8.11.3 2018-11-28 11:59:02 -06:00
Rob Winch ed90e4143e MIN_SPRING_VERSION is 4.3.21.RELEASE 2018-11-28 11:58:48 -06:00
Rob Winch 3747a14258 Update to Spring Session 1.3.4.RELEASE 2018-11-28 11:01:56 -06:00
Rob Winch 10fec400eb Update to Spring Data Ingalls-SR17 2018-11-28 11:01:39 -06:00
Rob Winch 315c0b3f03 Update to Jackson 2.8.11.20181123 2018-11-28 11:01:07 -06:00
Rob Winch 43677a6964 Update to CGLIB 3.2.9 2018-11-28 11:00:48 -06:00
Rob Winch 6d25f479b0 Update to AssertJ 2.6.0 2018-11-28 11:00:31 -06:00
Rob Winch 8f03a04b9a Update to Spring 4.3.21.RELEASE 2018-11-28 11:00:14 -06:00
Joe Grandja faefcc73e9 Update to spring-boot-gradle-plugin:1.5.17
Fixes gh-5831
2018-11-28 05:48:50 -05:00
Josh Cummings dfacad020b Register NullRequestCache When Disabled
Fixes: gh-6102
2018-11-20 10:57:57 -07:00
Erik van Paassen 0af0ee3339 Fix csrf:token-repository-ref XSD documentation
The documentation of the token-repository-ref attribute of the csrf
element in the schema has been updated to make clear the default
repository is lazy. Targets versions 4.2, 5.0 and 5.1.

Fixes gh-6037
2018-11-08 10:17:07 -06:00
Josh Cummings dca42b5602 Revert UnboundId to 3.2.1
The 3.x series is more aligned with the rest of the Spring ecosystem
at this point in history.

Fixes: gh-5984
2018-10-23 11:12:33 -06:00
Spring Buildmaster 657f0475ec Next development version 2018-10-16 03:23:34 +00:00
Spring Buildmaster 8e9f7e2f10 Release version 4.2.9.RELEASE 2018-10-16 03:23:29 +00:00
Spring Buildmaster bf5a3a1aee Fix to be latest SNAPSHOT 2018-10-15 21:52:13 -05:00
Rob Winch 201690ceba Update to Spring Session 1.3.3
Fixes: gh-5977
2018-10-15 20:43:20 -05:00
Rob Winch e1f33d577f Update to Spring Data Ingalls SR16
Fixes: gh-5976
2018-10-15 20:43:13 -05:00
Rob Winch 879adcae5f Update to Spring Boot 1.5.16.RELEASE
Fixes: gh-5975
2018-10-15 20:43:01 -05:00
Josh Cummings eed8538071 Password Modify Extended Operation Support
LdapUserDetailsManager can be configured to either use direct
attribute modification or the LDAP Password Modify Extended Operation
to change a user's password.

Fixes: gh-3392
2018-10-15 11:37:30 -06:00
Josh Cummings 3df9ad1e8f Introducing UnboundIdContainer
A container for running an embedded unboundid LDAP server.

Fixes: gh-5920
2018-10-15 11:37:23 -06:00
Johnny Lim dac46dc57c Add a missing space in Secured.value() signature 2018-10-03 14:50:26 -04:00
Rob Winch b5b2e2c50e Fix SwitchUserFilter matchers
Fixes: gh-4249
2018-09-14 09:51:53 -05:00
Rob Winch 72c99af0d4 AntPathRequestMatcher supports UrlPathHelper
Fixes: gh-5846
2018-09-14 09:51:53 -05:00
Joe Grandja 742e5fd7a9 Downgrade to spring-boot-gradle-plugin:1.5.2
Fixes gh-5829
2018-09-10 11:14:07 -04:00
Joe Grandja 795c073f48 Update to powermock:1.6.5
Fixes gh-5821
2018-09-10 09:06:41 -04:00
Joe Grandja 58c9cbb471 Update to Spring 4.3.19
Fixes gh-5826
2018-09-07 18:12:55 -04:00
Joe Grandja e40bc262bb Update to Spring Data Commons 1.13.14
Fixes gh-5825
2018-09-07 17:43:55 -04:00
Joe Grandja b0d865e28f Update tomcat:7.0.90
Fixes gh-5824
2018-09-07 17:43:55 -04:00
Joe Grandja 0f7f0042ac Update to Spring Boot 1.5.15
Fixes gh-5822
2018-09-07 17:43:55 -04:00
Joe Grandja e0f1121d5b Update to javax.servlet.jsp.jstl-api:1.2.2
Fixes gh-5820
2018-09-07 17:35:35 -04:00
Joe Grandja ea93ed4165 Update to jackson-databind:2.8.11.2
Fixes gh-5819
2018-09-07 17:35:35 -04:00
Joe Grandja 96acf33019 Update to httpcomponents:httpclient:4.2.5
Fixes gh-5818
2018-09-07 17:35:34 -04:00
Joe Grandja 35dbc0e6a8 Update to bcpkix-jdk15on:1.60
Fixes gh-5816
2018-09-07 17:35:34 -04:00
Joe Grandja 0526c5233c Update to aspectj:1.8.13
Fixes gh-5813
2018-09-07 15:56:38 -04:00
Joe Grandja 60c011a976 Update to org.jacoco.agent:0.7.9
Fixes gh-5812
2018-09-07 15:52:23 -04:00
Joe Grandja 916a19ccbd Update to logback-classic:1.1.11
Fixes gh-5811
2018-09-07 15:48:29 -04:00
Joe Grandja 8138fac3f9 Update to hsqldb:2.3.6
Fixes gh-5810
2018-09-07 15:42:45 -04:00
Joe Grandja 62fadfd28a Update to ehcache:2.10.5
Fixes gh-5809
2018-09-07 15:39:23 -04:00
Rob Winch 166f48e6ab Fix OptimizeAntPathRequestMatcher
Previously the logic for determining if the pathInfo should be appended
was inverted.

This correctly concatenates url + pathInfo if url is a non empty String.

Fixes: gh-5473
2018-08-21 11:53:22 -05:00
Christoph Dreis 0f97086c86 Optimize AntPathRequestMatcher.getRequestPath() 2018-08-21 11:53:22 -05:00
Johnny Lim fe5c6d6621 Fix typo
Closes #5579
2018-08-03 09:58:58 -05:00
Rob Winch c642de537a BasicAuthenticationFilter case insenstive
Fixes: gh-5617
2018-07-31 09:14:38 -05:00
Spring Buildmaster fd27c07b55 Next development version 2018-06-13 02:35:13 +00:00
Spring Buildmaster e0d95c7c8a Release version 4.2.7.RELEASES 2018-06-13 02:35:06 +00:00
Rob Winch 9d76c98791 Fix Checkstyle
Issue: gh-5323
2018-06-12 20:47:49 -05:00
Rob Winch e923371724 Update SpringSecurityCoreVersion 2018-06-12 17:24:16 -05:00
Rob Winch 216512bc54 Update to Spring Framework 4.3.18.RELEASE
Fixes: gh-5437
2018-06-12 17:21:46 -05:00
Rob Winch 8445e91b22 Add Assumptions.assumeMinimumJdk8
Certain cryptographic algorithms are only supported on JDK8+. This
causes failures in JDK 7. This commit adds a JUnit assumption on
tests that leverage JDK8 specific cryptographic algorithms.

Issue: gh-5323
2018-05-10 10:53:18 -05:00
Rob Winch 13ccb83d6f Remove java.util.Base64
java.util.Base64 was not added until JDK8, so we should use
Spring Security's Base64 in 4.x

Issue: gh-5323
2018-05-10 10:53:18 -05:00
Rob Winch 127d9eece9 Default Spring IO version Brussels-SR9
Fixes: gh-5326
2018-05-10 10:53:18 -05:00
Spring Buildmaster 7891787a53 Next development version 2018-05-08 17:14:38 +00:00
Spring Buildmaster 2d8b6650db Release version 4.2.6.RELEASE 2018-05-08 17:14:29 +00:00
Rob Winch 78995ff0a9 Use Spring Boot 1.5.2 to prevent deploy error 2018-05-08 11:35:18 -05:00
Rob Winch 7974f3161d spring-boot-gradle-plugin:1.5.0.RELEASE 2018-05-08 11:27:32 -05:00
Rob Winch c35c1c0643 Update Dependencies 2018-05-08 10:53:35 -05:00
Trygve Aasjord 2162221589 Pass username as second parameter for search filter.
Allows the username only (without domain) to be used in custom search filter like "sAMAccountName={1}",
in eg. situations where the userPrincipalName has a different suffix than domain.

Thanks to contributors in issue.

fixes gh-2448

(cherry picked from commit 8d717c62af)
2018-05-04 10:51:14 -05:00
Kazuki Shimizu 040fb6aa3c Fix incorrect explanation for customizing query on JdbcDaoImpl 2018-05-04 10:45:09 -05:00
Rob Winch b152218ee0 Add InMemoryUserDetailsManager(UserDetails...)
Fixes: gh-5304
2018-05-04 10:33:40 -05:00
Rob Winch 544e421157 Add UserBuilder Methods
Fixes: gh-5303
2018-05-04 10:33:25 -05:00
Rob Winch 0f612bf637 Add crypto PasswordEncoder from 5.0.x
Fixes: gh-5302
2018-05-04 10:32:53 -05:00
Rob Winch c683bc10bf Fixes: gh-5190 2018-04-16 17:51:51 -05:00
Spring Buildmaster 11ab23f4f4 Next development version 2018-03-30 16:34:47 +00:00
Spring Buildmaster 0065b55a75 Release version 4.2.5.RELEASE 2018-03-30 16:34:39 +00:00
Rob Winch d6f9d2e34a CookieClearingLogoutHandler adds uses contextPath + "/"
Fixes: gh-5141
2018-03-19 16:52:14 -05:00
Rob Winch 5dedbb6283 Update to jackson-databind-2.8.11.1
Fixes: gh-5101
2018-03-09 13:55:49 -06:00
Rob Winch 4cad151b57 Fix TestingAuthenticationTokenTests JDK 1.6 compile
Issue: gh-5097
2018-03-09 13:46:10 -06:00
Josh Cummings 72080bb5fe Authorities authenticate TestingAuthenticationToken
In other extensions of `AbstractAuthenticationToken`, the constructors
that include `authorities` call `setAuthenticated(true)`. This includes
`PreAuthenticated`-, `UsernamePassword`-, and
`RememberMeAuthenticationToken`.

This change brings `TestingAuthenticationToken` in line with that
convention.

Note that this was done once already to one of the constructors
(ee13be4) in `TestingAuthenticationToken` that takes an arity of
`authorities`. It was not propagated to the constructor that takes a
collection, which is what this commit remedies.

Fixes: gh-5097
2018-03-09 13:27:27 -06:00
Rob Winch 5854f00977 Fix StrictHttpFirewall rules
Fixes: gh-5093
2018-03-08 21:31:37 -06:00
Rob Winch 93118f4e91 Use HttpFirewall Bean
Fixes: gh-5025
2018-02-16 15:45:20 -06:00
Rob Winch 8796850816 Format HttpFirewall Reference
Put each sentence on a newline.

Issue: gh-5025
2018-02-16 15:41:18 -06:00
Rob Winch cee2ea9c60 Polish StrictHttpFirewall Javadoc
Also cleanup DefaultHttpFirewall Javadoc

Issue: gh-5009
2018-02-15 17:32:37 -06:00
Rob Winch 1159c9f302 Fix since on StrictHttpFirewall
Fixes: gh-5006
2018-02-08 14:14:52 -06:00
Rob Winch 6c5ce1237d Polish StrictHttpFirewall Javadoc
Fixes: gh-5009
2018-02-08 14:12:35 -06:00
Rob Winch f81b58112b Cache headers only if no cache headers set
Fixes: gh-5005
2018-02-07 14:57:20 -06:00
Spring Buildmaster 0e02b489c8 Next development version 2018-01-24 23:19:49 +00:00
Spring Buildmaster d1669b909f Release 4.2.4.RELEASE 2018-01-24 23:19:40 +00:00
Rob Winch cb8041ba67 Add StrictHttpFirewall 2018-01-24 16:31:40 -06:00
Rob Winch 6f74162a1f Test Jackson HashMap in Whitelist
Issue: gh-4889
2018-01-03 16:08:57 -06:00
Chris Burrell 99a0baadfa Add HashMap to Jackson whitelist
Issue: gh-4889
2018-01-03 16:08:28 -06:00
Rob Winch 1f9a0e579f Update Spring Data Ingalls SR8
Fixes gh-4785
2017-11-02 16:34:40 -05:00
Rob Winch 9e7d08c9e7 Update to Boot 1.5.8.RELEASE
Fixes gh-4784
2017-11-02 16:20:43 -05:00
Rob Winch 82168faf9d Update to jsonassert 1.4.0
Fixes gh-4783
2017-11-02 16:19:58 -05:00
Rob Winch 9d0f8977a9 Update to slfj4 1.7.25
Fixes gh-4782
2017-11-02 16:19:16 -05:00
Rob Winch 5ae615f3b4 Update Jackson to 2.8.10
Fixes gh-4781
2017-11-02 16:18:31 -05:00
Rob Winch d2b0077392 Update Hibernate Versions
- Hibernate to 5.0.12.Final
- Hibernate validator to 5.3.6.Final

Fixes gh-4780
2017-11-02 16:17:46 -05:00
Rob Winch 092c5aecf7 Update to Ehcache 2.10.4
Fixes gh-4779
2017-11-02 16:13:43 -05:00
Rob Winch a5d56d8724 Update to Aspectj 1.8.12
Fixes gh-4778
2017-11-02 16:12:39 -05:00
Rob Winch 7c0da854da Update to Spring LDAP 2.3.2
Fixes gh-4777
2017-11-02 16:11:03 -05:00
Rob Winch 0f546dcb07 Update to Spring 4.3.12
Fixes gh-4776
2017-11-02 16:08:50 -05:00
Rob Winch cb576d16e1 DelegatingApplicationListener uses CopyOnWriteArrayList
Fixes gh-4417
2017-11-02 14:41:20 -05:00
Greg Turnquist 3b4df40f47 Fix UsernamePasswordAuthenticationTokenMixin to handle null credentials/details
Fixes gh-4773
2017-11-02 14:41:20 -05:00
Gajendra kumar 6cbf71bd72 Allow inject Map into SessionRegistryImpl
As principals and sessionIds are set in class itself so one can't share
user session count across nodes(Cluster). Using constructor for setting
principals and sessionIds we can pass Cache map to constructor which can
enable common session count in cluster otherwise user would be allowed to
logged in with multiple sessions. There is no point keeping principals
and sessionIds completely internal.

Fixes gh-4772
2017-11-02 14:41:20 -05:00
Rob Winch cd63329b63 Polish XFrameOptionsHeaderWriter
Fixes: gh-4771
2017-11-02 14:41:20 -05:00
Nathan Wong cc7f504f96 Add check to see if return value is DENY
Originally, if the return from getAllowFromValue(request) is "DENY",
then the X-Frame-Options header's value will proceed to be written as
"ALLOW FROM DENY" - an invalid value.

This commit adds a condition in the if clause that checks whether
allowFromValue is "DENY". This way, the X-Frame-Options header will be
written as "ALLOW FROM origin" or "DENY".

Issue gh-4771
2017-11-02 14:41:20 -05:00
Antoine a094563052 Fix leading space characters reported by checkstyle 2017-11-02 14:41:20 -05:00
Rob Winch da19435f21 Fix assertj
Fix for 4.2.x
2017-11-02 14:41:02 -05:00
Antoine be50cd8ada Polish more AssertJ assertions
Issue gh-4770
2017-11-02 14:40:53 -05:00
Antoine 21efbb6ba7 Polish AssertJ assertions
Fixes gh-4770
2017-11-02 14:40:53 -05:00
Arend v. Reinersdorff c7cf6fdd73 Minor typos PreAuthenticatedAuthenticationProvider
Fixes gh-4769
2017-11-02 14:40:53 -05:00
Rob Winch 8129bf2ce0 Update .gitignore
- ignore classes/
- ignore s101plugin.state
2017-11-02 14:40:53 -05:00
Joris Portegies Zwart d48079eb19 JavaDoc for Pbkdf2PasswordEncoder refer to constants
Fix Javadoc so that it uses the actual values for default hash width and number of iterations

Fixes gh-4768
2017-11-02 14:40:53 -05:00
Kyle Anderson 45f1179b52 Fix Typo in Reference Docs
Fixes gh-4767
2017-11-02 14:40:52 -05:00
Rob Winch e11dfa7578 Lookup HandlerMappingIntrospector from Bean 2017-11-02 14:40:52 -05:00
Frank Pavageau 6cc0f6c054 Deserialize the principal in a neutral way
When the principal of the Authentication is an object, it is not necessarily
an User: it could be another implementation of UserDetails, or even a
completely unrelated type. Since the type of the object is serialized as a
property and used by the deserialization anyway, there's no point in
enforcing a stricter type.
2017-10-31 16:42:50 -05:00
Frank Pavageau 22ea835643 Map values directly from the JSON nodes
Not only is it more efficient without converting to an intermediate String,
using JsonNode.toString() may not even produce valid JSON according to its
Javadoc (ObjectMapper.writeValueAsString() should be used).
2017-10-31 16:42:50 -05:00
linzhaoming 9f51d68e92 Fix wrong doc of HttpServletRequest.authenticate()
Should be HttpServletRequest.authenticate(HttpServletResponse response), should not include argument HttpServletRequest
2017-10-30 01:01:44 -05:00
linzhaoming 32af1884f7 Fix wrong typo: DigestAuthenticatonEntryPoint to DigestAuthenticationEntryPoint
Fix wrong type
2017-10-30 01:01:44 -05:00
Chaouki Dhib a88035196a Fix typo in the doc in 5.7 Multiple HttpSecurity 2017-10-12 07:43:55 -05:00
Spring Buildmaster 0db94b1d36 Next development version 2017-06-08 04:34:44 +00:00
Spring Buildmaster 9e8994a2b7 Release version 4.2.3.RELEASE 2017-06-08 04:34:34 +00:00
Rob Winch 8b2faff7ad Update to Spring 4.3.9.RELEASE
Fixes gh-4375
2017-06-07 22:52:58 -05:00
Rob Winch 469bc20e6d UrlUtils reuses ABSOLUTE_URL
Fixes gh-4234
2017-06-07 22:52:58 -05:00
Rob Winch 947d11f433 Update SecurityJackson2Modules
Fixes gh-4370
2017-06-07 22:52:58 -05:00
Rob Winch b3a60a83f6 Force springIoTestRuntime assertj.version=2.2.0 2017-05-18 18:02:33 -05:00
Rob Winch 5bc7e4171c Fix DefaultSavedRequestMixinTests with Spring 5
Previously DefaultSavedRequestMixinTests
serializeDefaultRequestBuildWithConstructorTest broke in Spring 5
because Spring 5's MockHttpServletRequest.setCookie now automatically adds
the Cookie header.

This commit ensures that the Cookie header is not added by overriding the
class we are writing.

Fixes gh-4272
2017-05-18 17:57:18 -05:00
Rob Winch 80e96b0f7b Use Spring IO Brussels-SR1 2017-03-21 14:39:46 -05:00
7748 changed files with 182388 additions and 735548 deletions
+7 -12
View File
@@ -1,22 +1,17 @@
# EditorConfig for Spring Security
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc#mind-the-whitespace
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md#mind-the-whitespace
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
charset = latin1
[*.{java,xml}]
# 4 tabs indentation
indent_style = tab
indent_size = 4
charset = utf-8
continuation_indent_size = 8
tab_width = 4
ij_smart_tabs = false
ij_java_align_multiline_parameters = false
[*.gradle]
indent_style = tab
trim_trailing_whitespace = true
-18
View File
@@ -1,18 +0,0 @@
# Normalize line endings to auto.
* text auto
# Ensure that line endings for DOS batch files are not modified.
*.bat -text
# Ensure the following are treated as binary.
*.cer binary
*.graffle binary
*.jar binary
*.jpeg binary
*.jpg binary
*.keystore binary
*.odg binary
*.otg binary
*.png binary
*.hsx binary
*.serialized binary
-4
View File
@@ -1,7 +1,3 @@
<!--
For Security Vulnerabilities, please use https://spring.io/security-policy
-->
### Summary
<!--
-28
View File
@@ -1,28 +0,0 @@
---
name: Bug
about: Create a bug report to help us improve
title: ''
labels: 'status: waiting-for-triage, type: bug'
assignees: ''
---
<!--
Do NOT report Security Vulnerabilities here. Please use https://github.com/spring-projects/spring-security/security/policy
-->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Sample**
A link to a GitHub repository with a [minimal, reproducible sample](https://stackoverflow.com/help/minimal-reproducible-example).
Reports that include a sample will take priority over reports that do not.
At times, we may require a sample, so it is good to try and include a sample up front.
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Community Support
url: https://stackoverflow.com/questions/tagged/spring-security
about: Please ask and answer questions on StackOverflow with the tag `spring-security`.
-25
View File
@@ -1,25 +0,0 @@
---
name: Enhancement
about: Suggest an enhancement for this project
title: ''
labels: 'status: waiting-for-triage, type: enhancement'
assignees: ''
---
**Expected Behavior**
<!--- Tell us how it should work -->
**Current Behavior**
<!--- Explain the difference from current behavior -->
**Context**
<!---
How has this issue affected you?
What are you trying to accomplish?
What other alternatives have you considered?
Are you aware of any workarounds?
-->
+1 -7
View File
@@ -1,9 +1,3 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Before creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
-->
-2
View File
@@ -1,2 +0,0 @@
require:
members: false
-203
View File
@@ -1,203 +0,0 @@
version: 2
registries:
shibboleth:
type: maven-repository
url: https://build.shibboleth.net/maven/releases
updates:
# 6.5.x
- package-ecosystem: gradle
target-branch: 6.5.x
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
- 'in: build'
registries:
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:*
- dependency-name: org.junit:junit-bom
update-types:
- version-update:semver-major
- dependency-name: org.mockito:mockito-bom
update-types:
- version-update:semver-major
- dependency-name: '*'
update-types:
- version-update:semver-major
- version-update:semver-minor
- package-ecosystem: npm
target-branch: 6.5.x
directory: /docs
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: 6.5.x
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
# 7.0.x
- package-ecosystem: gradle
target-branch: 7.0.x
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
- 'in: build'
registries:
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: io.spring.nullability:*
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:*
- dependency-name: org.junit:junit-bom
update-types:
- version-update:semver-major
- dependency-name: org.mockito:mockito-bom
update-types:
- version-update:semver-major
- dependency-name: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*'
update-types:
- version-update:semver-major
- version-update:semver-minor
- package-ecosystem: npm
target-branch: 7.0.x
directory: /docs
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: 7.0.x
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
# main
- package-ecosystem: gradle
target-branch: main
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
- 'in: build'
registries:
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:*
- dependency-name: org.junit:junit-bom
update-types:
- version-update:semver-major
- dependency-name: org.mockito:mockito-bom
update-types:
- version-update:semver-major
- dependency-name: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*'
update-types:
- version-update:semver-major
- package-ecosystem: npm
target-branch: main
directory: /docs
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: main
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
# docs-build
- package-ecosystem: gradle
target-branch: docs-build
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
registries:
- shibboleth
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- dependency-name: org.apache.directory.shared:*
- dependency-name: org.junit:junit-bom
update-types:
- version-update:semver-major
- dependency-name: org.mockito:mockito-bom
update-types:
- version-update:semver-major
- dependency-name: com.gradle.enterprise
update-types:
- version-update:semver-major
- version-update:semver-minor
- dependency-name: '*'
update-types:
- version-update:semver-major
- package-ecosystem: npm
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
- package-ecosystem: github-actions
target-branch: docs-build
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'type: dependency-upgrade'
- 'in: build'
@@ -1,17 +0,0 @@
name: Merge Dependabot PR
on:
pull_request:
branches:
- main
- '*.x'
- 'docs-build'
run-name: Merge Dependabot PR ${{ github.ref_name }}
jobs:
merge-dependabot-pr:
permissions: write-all
uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@0d3f15bb384839966a1ff5c4383731a2b747f24b # v7
with:
mergeArguments: --auto --rebase
-36
View File
@@ -1,36 +0,0 @@
name: CI
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
permissions:
contents: read
jobs:
snapshot-test:
name: Test Against Snapshots
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
strategy:
matrix:
include:
- java-version: 25
toolchain: 25
with:
java-version: ${{ matrix.java-version }}
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.0.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ -PmicrometerVersion=1.+ --stacktrace
secrets: inherit
send-notification:
name: Send Notification
needs: [ snapshot-test ]
if: ${{ !success() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
@@ -1,23 +0,0 @@
name: Clean build artifacts
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
permissions:
contents: read
jobs:
main:
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Delete artifacts in cron job
env:
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: |
echo "Running clean build artifacts logic"
output=$(curl -X GET -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts | grep '"id"' | cut -d : -f2 | sed 's/,*$//g')
echo Output is $output
for id in $output; do curl -X DELETE -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts/$id; done;
-17
View File
@@ -1,17 +0,0 @@
name: "CodeQL Advanced"
on:
push:
pull_request:
workflow_dispatch:
schedule:
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule
- cron: '0 5 * * *'
permissions: read-all
jobs:
codeql-analysis-call:
permissions:
actions: read
contents: read
security-events: write
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@e415dadd0910c901e7a7fabd67bbb355b2324500 # 1
@@ -1,69 +0,0 @@
name: CI
on:
push:
branches-ignore:
- "dependabot/**"
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
permissions:
contents: read
jobs:
build:
name: Build
uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 25 ]
with:
runs-on: ${{ matrix.os }}
java-version: ${{ matrix.jdk }}
distribution: temurin
secrets: inherit
deploy-artifacts:
name: Deploy Artifacts
needs: [ build ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
default-publish-milestones-central: true
java-version: 25
secrets: inherit
deploy-schema:
name: Deploy Schema
needs: [ build ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
java-version: 25
secrets: inherit
perform-release:
name: Perform Release
needs: [ deploy-artifacts, deploy-schema ]
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
milestone-repo-url: https://repo1.maven.org/maven2
release-repo-url: https://repo1.maven.org/maven2
artifact-path: org/springframework/security/spring-security-core
slack-announcing-id: spring-security-announcing
java-version: 25
secrets: inherit
send-notification:
name: Send Notification
needs: [ perform-release ]
if: ${{ !success() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
-76
View File
@@ -1,76 +0,0 @@
name: Defer Issues
on:
workflow_dispatch:
permissions:
contents: read
jobs:
defer-issues:
name: Defer Issues
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
permissions:
issues: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Compute Version
id: compute-version
uses: spring-io/spring-release-actions/compute-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
- name: Get Today's Release Version
id: todays-release
uses: spring-io/spring-release-actions/get-todays-release-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
snapshot-version: ${{ steps.compute-version.outputs.version }}
milestone-repository: ${{ github.repository }}
milestone-token: ${{ secrets.GITHUB_TOKEN }}
- name: Compute Next Version
id: next-version
uses: spring-io/spring-release-actions/compute-next-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
version: ${{ steps.todays-release.outputs.release-version }}
- name: Schedule Next Milestone
uses: spring-io/spring-release-actions/schedule-milestone@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
version: ${{ steps.next-version.outputs.version }}
version-date: ${{ steps.next-version.outputs.version-date }}
repository: ${{ github.repository }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Move Open Issues to Next Milestone
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_MILESTONE: ${{ steps.todays-release.outputs.release-version }}
NEXT_MILESTONE: ${{ steps.next-version.outputs.version }}
run: |
current_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
--jq ".[] | select(.title == \"$CURRENT_MILESTONE\") | .number")
if [ -z "$current_milestone_number" ]; then
echo "No milestone found for $CURRENT_MILESTONE"
exit 0
fi
next_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
--jq ".[] | select(.title == \"$NEXT_MILESTONE\") | .number")
if [ -z "$next_milestone_number" ]; then
echo "No milestone found for $NEXT_MILESTONE"
exit 1
fi
echo "Moving open issues from milestone '$CURRENT_MILESTONE' (#$current_milestone_number) to '$NEXT_MILESTONE' (#$next_milestone_number)"
page=1
while true; do
issues=$(gh api "repos/${{ github.repository }}/issues?milestone=$current_milestone_number&state=open&per_page=100&page=$page" \
--jq '.[].number')
if [ -z "$issues" ]; then
break
fi
for issue in $issues; do
echo "Moving issue/PR #$issue to milestone $NEXT_MILESTONE"
gh api repos/${{ github.repository }}/issues/$issue \
--method PATCH \
--field milestone=$next_milestone_number \
--silent
done
page=$((page + 1))
done
echo "Done."
-33
View File
@@ -1,33 +0,0 @@
name: Deploy Docs
on:
push:
branches-ignore:
- "gh-pages"
- "dependabot/**"
tags: '**'
repository_dispatch:
types: request-build-reference # legacy
#schedule:
#- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects'
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: docs-build
fetch-depth: 1
- name: Dispatch (partial build)
if: github.ref_type == 'branch'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
- name: Dispatch (full build)
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
-27
View File
@@ -1,27 +0,0 @@
name: Finalize Release
on:
workflow_dispatch: # Manual trigger
inputs:
version:
description: The Spring Security release to finalize (e.g. 7.0.0-RC2)
required: true
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
permissions:
contents: read
jobs:
perform-release:
name: Perform Release
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
should-perform-release: true
project-version: ${{ inputs.version }}
milestone-repo-url: https://repo1.maven.org/maven2
release-repo-url: https://repo1.maven.org/maven2
artifact-path: org/springframework/security/spring-security-core
slack-announcing-id: spring-security-announcing
secrets: inherit
@@ -1,34 +0,0 @@
name: Execute Gradle Wrapper Upgrade
on:
schedule:
- cron: '0 2 * * *' # 2am UTC
workflow_dispatch:
permissions:
pull-requests: write
jobs:
upgrade_wrapper:
name: Execution
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest
steps:
- name: Set up Git configuration
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config --global url."https://unused-username:${TOKEN}@github.com/".insteadOf "https://github.com/"
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up JDK 25
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
with:
java-version: '25'
distribution: 'temurin'
- name: Set up Gradle
uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
- name: Upgrade Wrappers
run: ./gradlew clean upgradeGradleWrapperAll --continue -Porg.gradle.java.installations.auto-download=false
env:
WRAPPER_UPGRADE_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,35 +0,0 @@
name: Check Milestone
on:
milestone:
types: [created, opened, edited]
env:
DUE_ON: ${{ github.event.milestone.due_on }}
TITLE: ${{ github.event.milestone.title }}
permissions:
contents: read
jobs:
spring-releasetrain-checks:
name: Check DueOn is on a Release Date
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
permissions:
contents: none
steps:
- name: Print Milestone Being Checked
run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'"
- name: Validate DueOn
if: env.DUE_ON != ''
run: |
export TOOL_VERSION=0.1.1
wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar"
java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3
send-notification:
name: Send Notification
needs: [ spring-releasetrain-checks ]
if: ${{ failure() || cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
-51
View File
@@ -1,51 +0,0 @@
name: PR Build
on: pull_request
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
with:
java-version: '25'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
generate-docs:
name: Generate Docs
runs-on: ubuntu-latest
if: ${{ github.repository == 'spring-projects/spring-security' }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up gradle
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
with:
java-version: '25'
distribution: 'temurin'
- name: Run Antora
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
- name: Upload Docs
id: upload
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docs
path: docs/build/site
overwrite: true
send-notification:
name: Send Notification
needs: [ build, generate-docs ]
if: ${{ failure() && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
-24
View File
@@ -1,24 +0,0 @@
name: Release Scheduler
on:
schedule:
- cron: '15 15 * * MON' # Every Monday at 3:15pm UTC
workflow_dispatch:
permissions: read-all
jobs:
dispatch_scheduled_releases:
name: Dispatch scheduled releases
if: github.repository_owner == 'spring-projects'
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 7.0.x, 6.5.x, 6.4.x, 6.3.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 1
- name: Dispatch
env:
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }}
@@ -1,37 +0,0 @@
name: Update Antora UI Spring
on:
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch:
permissions:
pull-requests: write
issues: write
contents: write
jobs:
update-antora-ui-spring:
name: Update on Supported Branches
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest
strategy:
matrix:
branch: [ '6.5.x', '7.0.x', 'main' ]
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
name: Update
with:
docs-branch: ${{ matrix.branch }}
token: ${{ secrets.GITHUB_TOKEN }}
antora-file-path: 'docs/antora-playbook.yml'
update-antora-ui-spring-docs-build:
name: Update on docs-build
if: ${{ github.repository == 'spring-projects/spring-security' }}
runs-on: ubuntu-latest
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
name: Update
with:
docs-branch: 'docs-build'
token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,23 +0,0 @@
name: Update Scheduled Release Version
on:
workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main.
permissions:
contents: read
jobs:
update-scheduled-release-version:
name: Update Scheduled Release Version
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
secrets: inherit
send-notification:
name: Send Notification
needs: [ update-scheduled-release-version ]
if: ${{ failure() || cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Send Notification
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
+2 -10
View File
@@ -1,4 +1,3 @@
classes/
target/
*/src/*/java/META-INF
*/src/META-INF/
@@ -8,7 +7,7 @@ target/
.project
.DS_Store
.settings/
.idea/*
.idea/
out/
bin/
intellij/
@@ -22,12 +21,5 @@ build/
atlassian-ide-plugin.xml
!etc/eclipse/.checkstyle
.checkstyle
classes/
s101plugin.state
.attach_pid*
.~lock.*#
.kotlin/
!.idea/checkstyle-idea.xml
!.idea/externalDependencies.xml
node_modules
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA">
<option name="configuration">
<map>
<entry key="checkstyle-version" value="8.14" />
<entry key="copy-libs" value="false" />
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="scan-before-checkin" value="false" />
<entry key="scanscope" value="JavaOnlyWithTests" />
<entry key="suppress-errors" value="false" />
</map>
</option>
</component>
</project>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalDependencies">
<plugin id="CheckStyle-IDEA" />
<plugin id="org.jetbrains.plugins.gradle" />
</component>
</project>
-6
View File
@@ -1,6 +0,0 @@
# Use sdkman to run "sdk env" to initialize with correct JDK version
# Enable auto-env through the sdkman_auto_env config
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
java=25-librca
+16
View File
@@ -0,0 +1,16 @@
language: java
jdk:
- oraclejdk8
os:
- linux
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
script: ./gradlew build
-3
View File
@@ -1,3 +0,0 @@
{
"java.gradle.buildServer.enabled": "off"
}
+44
View File
@@ -0,0 +1,44 @@
= Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open
and welcoming community, we pledge to respect all people who contribute through reporting
issues, posting feature requests, updating documentation, submitting pull requests or
patches, and other activities.
We are committed to making participation in this project a harassment-free experience for
everyone, regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses,
without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
consistently applying these principles to every aspect of managing this project. Project
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
be reviewed and investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
-146
View File
@@ -1,146 +0,0 @@
= Contributing to Spring Security
First off, thank you for taking the time to contribute! :+1: :tada:
== Table of Contents
* <<code-of-conduct>>
* <<how-to-contribute>>
* <<ask-questions>>
* <<find-an-issue>>
* <<create-an-issue>>
* <<issue-lifecycle>>
* <<submit-a-pull-request>>
* <<build-from-source>>
* <<code-style>>
[[code-of-conduct]]
== Code of Conduct
This project is governed by the https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[Spring code of conduct].
By participating you are expected to uphold this code.
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
[[how-to-contribute]]
== How to Contribute
[[ask-questions]]
=== Ask Questions
If you have a question, check Stack Overflow using
https://stackoverflow.com/questions/tagged/spring-security+or+spring-ldap+or+spring-authorization-server+or+spring-session?tab=Newest[this list of tags].
Find an existing discussion, or start a new one if necessary.
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
Reading those discussions helps you to learn about the issue, and helps us to make a decision.
[[find-an-issue]]
=== Find an Existing Issue
There are many issues in Spring Security with the labels https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+ideal-for-contribution%22[`ideal-for-contribution`] or https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+first-timers-only%22[`first-timers-only`] that are a great way to contribute to a discussion or <<submit-a-pull-request,to a PR>>.
You can volunteer by commenting on these tickets, and we will assign them to you.
[[create-an-issue]]
=== Create an Issue
Reporting an issue or making a feature request is a great way to contribute.
Your feedback and the conversations that result from it provide a continuous flow of ideas.
However, before creating a ticket, please take the time to <<ask-questions,ask and research>> first.
If you create an issue after a discussion on Stack Overflow, please provide a description in the issue instead of simply referring to Stack Overflow.
The issue tracker is an important place of record for design discussions and should be self-sufficient.
Once you're ready, create an issue on https://github.com/spring-projects/spring-security/issues[GitHub].
Many issues are caused by subtle behavior, typos, and unintended configuration.
Creating a https://stackoverflow.com/help/minimal-reproducible-example[Minimal Reproducible Example] (starting with https://start.spring.io for example) of the problem helps the team quickly triage your issue and get to the core of the problem.
We love contributors, and we may ask you to <<submit-a-pull-request,submit a PR with a fix>>.
[[issue-lifecycle]]
=== Issue Lifecycle
When an issue is first created, it is flagged `waiting-for-triage` waiting for a team member to triage it.
Once the issue has been reviewed, the team may ask for further information if needed, and based on the findings, the issue is either assigned a target branch (or no branch if a feature) or is closed with a specific status.
The target branch is https://spring.io/projects/spring-security#support[the earliest supported branch] where <<choose-a-branch,the change will be applied>>.
When a fix is ready, the issue is closed and may still be re-opened until the fix is released.
After that the issue will typically no longer be reopened.
In rare cases if the issue was not at all fixed, the issue may be re-opened.
In most cases however any follow-up reports will need to be created as new issues with a fresh description.
[[build-from-source]]
=== Build from Source
See https://github.com/spring-projects/spring-security/tree/main#building-from-source[Build from Source] for instructions on how to check out, build, and import the Spring Security source code into your IDE.
[[code-style]]
=== Source Code Style
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
Additionally, since Streams are https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loops, please use them judiciously.
The team may ask you to change to a `for` loop if the given code is along a hot path.
To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
[[submit-a-pull-request]]
=== Submit a Pull Request
We are excited for your pull request! :heart:
Please do your best to follow these steps.
Don't worry if you don't get them all correct the first time, we will help you.
1. [[sign-cla]] All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.
For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring].
2. [[create-an-issue-list]] Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier to discuss with the team first to determine the right fix or enhancement.
For typos and straightforward bug fixes, starting with a pull request is encouraged.
Please include a description for context and motivation.
Note that the team may close your pull request if it's not a fit for the project.
3. [[choose-a-branch]] Always check out the branch indicated in the milestone and submit pull requests against it (for example, for milestone `5.8.3` use the `5.8.x` branch).
If there is no milestone, choose `main`.
Once merged, the fix will be forwarded-ported to applicable branches including `main`.
4. [[create-a-local-branch]] Create a local branch
If this is for an issue, consider a branch name with the issue number, like `gh-22276`.
5. [[write-tests]] Add documentation and JUnit Tests for your changes.
6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
9. [[format-code]] For each commit, build the code using `./gradlew format && ./gradlew check`.
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent
multiple edits or corrections of the same logical change.
See https://git-scm.com/book/en/Git-Tools-Rewriting-History[Rewriting History section of Pro Git] for an overview of streamlining the commit history.
11. [[format-commit-messages]] Format commit messages using 55 characters for the subject line, 72 characters per line
for the description, followed by the issue fixed, for example, `Closes gh-22276`.
See the https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines[Commit Guidelines section of Pro Git] for best practices around commit messages, and use `git log` to see some examples.
Favor imperative tense over present tense (use "Fix" instead of "Fixes"); avoid past tense (use "Fix" instead of "Fixed").
+
[indent=0]
----
Address NullPointerException
Closes gh-22276
----
[[reference-issue]]
1. If there is a prior issue, reference the GitHub issue number in the description of the pull request.
+
[indent=0]
----
Closes gh-22276
----
If accepted, your contribution may be heavily modified as needed prior to merging.
You will likely retain author attribution for your Git commits granted that the bulk of your changes remain intact.
You may also be asked to rework the submission.
If asked to make corrections, simply push the changes against the same branch, and your pull request will be updated.
In other words, you do not need to create a new pull request when asked to make changes.
When it is time to merge, you'll be asked to squash your commits.
==== Participate in Reviews
Helping to review pull requests is another great way to contribute.
Your feedback can help to shape the implementation of new features.
When reviewing pull requests, however, please refrain from approving or rejecting a PR unless you are a core committer for Spring Security.
+205
View File
@@ -0,0 +1,205 @@
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
# Code of Conduct
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.adoc).
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
# Similar but different
Each Spring module is slightly different than another in terms of team size, number of issues, etc. Therefore each project is managed slightly different. You will notice that this document is very similar to the [Spring Framework Contributor guidelines](https://github.com/SpringSource/spring-framework/wiki/Contributor-guidelines). However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
# Importing into IDE
The following provides information on setting up a development environment that can run the sample in [Spring Tool Suite 3.6.0+](https://www.springsource.org/sts). Other IDE's should work using Gradle's IDE support, but have not been tested.
* IDE Setup
* Install Spring Tool Suite 3.6.0+
* You will need the following plugins installed (can be found on the Extensions Page)
* Gradle Eclipse
* Groovy Eclipse
* Importing the project into Spring Tool Suite
* File->Import...->Gradle Project
# Understand the basics
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent [help documentation first](https://help.github.com/articles/using-pull-requests).
# Search GitHub issues; create an issue if necessary
Is there already an issue that addresses your concern? Do a bit of searching in our [GitHub issues ](https://github.com/spring-projects/spring-security/issues) to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
# Discuss non-trivial contribution ideas with committers
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the [Spring Security Gitter](https://gitter.im/spring-projects/spring-security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
# Sign the Contributor License Agreement
If you have not previously done so, please fill out and
submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring).
# Create your branch from master
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
# Use short branch names
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. 'gh-1234' or 'gh-1234-fix-npe'. Otherwise, use succinct, lower-case, dash (-) delimited names, such as 'fix-warnings', 'fix-typo', etc. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
#Keep commits focused
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
# Mind the whitespace
Please carefully follow the whitespace and formatting conventions already present in the framework.
1. Tabs, not spaces
1. Unix (LF), not dos (CRLF) line endings
1. Eliminate all trailing whitespace
1. Aim to wrap code at 120 characters, but favor readability over wrapping
1. Preserve existing formatting; i.e. do not reformat code for its own sake
1. Search the codebase using git grep and other tools to discover common naming conventions, etc.
1. Latin-1 (ISO-8859-1) encoding for Java sources; use native2ascii to convert if necessary
Whitespace management tips
1. You can use the [AnyEdit Eclipse plugin](https://marketplace.eclipse.org/content/anyedit-tools) to ensure spaces are used and to clean up trailing whitespaces.
1. Use git's pre-commit.sample hook to prevent invalid whitespace from being pushed out. You can enable it by moving ~/spring-security/.git/hooks/pre-commit.sample to ~/spring-security/.git/hooks/pre-commit and ensuring it is executable. For more information on hooks refer to [Pro Git's Pre-Commit Hook's section](https://git-scm.com/book/cs/ch7-3.html)
# Add Apache license header to all new classes
<pre>
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ...;
</pre>
# Update Apache license header to modified files as necessary
Always check the date range in the license header. For example, if you've modified a file in 2012 whose header still reads
<pre>
* Copyright 2002-2011 the original author or authors.
</pre>
then be sure to update it to 2012 appropriately
<pre>
* Copyright 2002-2012 the original author or authors.
</pre>
# Use @since tags for newly-added public API types and methods
e.g.
<pre>
/**
* ...
*
* @author First Last
* @since 3.2
* @see ...
*/
</pre>
# Submit JUnit test cases for all behavior changes
Search the codebase to find related unit tests and add additional `@Test` methods within.
1. Any new tests should end in the name Tests (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
2. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with @Test.
# Update spring-security-x.y.rnc for schema changes
Update the [RELAX NG](https://relaxng.org/) schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
<pre>
./gradlew spring-security-config:rncToXsd
</pre>
Changes to the XML schema will be overwritten by the Gradle build task.
# Squash commits
Use git rebase --interactive, git add --patch and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for git, there are many resources online to help you understand how these tools work. Here is one: https://book.git-scm.com/4_interactive_rebasing.html.
# Use real name in git commits
Please configure git to use your real first and last name for any commits you intend to submit as pull requests. For example, this is not acceptable:
<pre>
Author: Nickname &lt;user@mail.com&gt;
</pre>
Rather, please include your first and last name, properly capitalized, as submitted against the SpringSource contributor license agreement:
<pre>
Author: First Last &lt;user@mail.com&gt;
</pre>
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like git shortlog and others.
You can configure this globally via the account admin area GitHub (useful for fork-and-edit cases); globally with
<pre>
git config --global user.name "First Last"
git config --global user.email user@mail.com
</pre>
or locally for the spring-security repository only by omitting the '--global' flag:
<pre>
cd spring-security
git config user.name "First Last"
git config user.email user@mail.com
</pre>
# Format commit messages
<pre>
Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
single space, with blank lines in between, but conventions vary here
Fixes gh-123
</pre>
1. Keep the subject line to 50 characters or less if possible
2. Do not end the subject line with a period
3. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
3. Include Fixes gh-<issue-number> at the end if this fixes a GitHub issue
# Run all tests prior to submission
<pre>
cd spring-security
./gradlew clean build integrationTest
</pre>
# Submit your pull request
Subject line:
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
In the body:
1. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
2. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
3. Mention any GitHub Issues
4. Also mention that you have submitted the CLA as described above
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
# Mention your pull request on the associated GitHub issue
Add a comment to the associated GitHub issue(s) linking to your new pull request.
# Expect discussion and rework
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
Note that you can always force push (git push -f) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
-202
View File
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+17 -52
View File
@@ -1,30 +1,27 @@
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
image:https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml"]
image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"]
image:https://travis-ci.org/spring-projects/spring-security.svg?branch=master["Build Status", link="https://travis-ci.org/spring-security/spring-security"]
= Spring Security
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 6.0 requires Spring 6.0 as
a minimum and also requires Java 17.
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
a minimum and also requires Java 5.
For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects].
== Code of Conduct
Please see our https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[code of conduct]
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
== Downloading Artifacts
See https://docs.spring.io/spring-security/reference/getting-spring-security.html[Getting Spring Security] for how to obtain Spring Security.
See https://github.com/spring-projects/spring-framework/wiki/Downloading-Spring-artifacts[downloading Spring artifacts] for Maven repository information.
== Documentation
Be sure to read the https://docs.spring.io/spring-security/reference/[Spring Security Reference].
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/api/[Spring Security API Documentation].
You may also want to check out https://docs.spring.io/spring-security/reference/whats-new.html[what's new in the latest release].
Be sure to read the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference].
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/apidocs/[Spring Security API Documentation].
== Quick Start
See https://docs.spring.io/spring-security/reference/servlet/getting-started.html[Hello Spring Security] to get started with a "Hello, World" application.
We recommend you visit https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference] and read the "Getting Started" page.
== Building from Source
Spring Security uses a https://gradle.org[Gradle]-based build system.
@@ -32,9 +29,9 @@ In the instructions below, https://vimeo.com/34436402[`./gradlew`] is invoked fr
a cross-platform, self-contained bootstrap mechanism for the build.
=== Prerequisites
https://docs.github.com/en/get-started/quickstart/set-up-git[Git] and the https://www.oracle.com/java/technologies/downloads/#java17[JDK17 build].
https://help.github.com/set-up-git-redirect[Git] and the https://www.oracle.com/technetwork/java/javase/downloads[JDK8 build].
Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder extracted from the JDK download.
Be sure that your `JAVA_HOME` environment variable points to the `jdk1.8.0` folder extracted from the JDK download.
=== Check out sources
[indent=0]
@@ -42,59 +39,27 @@ Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder
git clone git@github.com:spring-projects/spring-security.git
----
=== Install all `spring-*.jar` into your local Maven repository.
=== Install all spring-\* jars into your local Maven cache
[indent=0]
----
./gradlew publishToMavenLocal
./gradlew install
----
=== Compile and test; build all JARs, distribution zips, and docs
=== Compile and test; build all jars, distribution zips, and docs
[indent=0]
----
./gradlew build
----
The reference docs are not currently included in the distribution zip.
You can build the reference docs for this branch by running the following command:
----
./gradlew :spring-security-docs:antora
----
That command publishes the docs site to the `_docs/build/site_` directory.
The https://github.com/spring-projects/spring-security/tree/docs-build[playbook branch] describes how to build the reference docs in detail.
Discover more commands with `./gradlew tasks`.
=== IDE setup (IntelliJ)
No special steps are needed to open Spring Security in IntelliJ.
=== IDE setup (Eclipse and VS Code)
To work in Eclipse or VS Code, first generate Eclipse metadata so you can import the project into Eclipse or VS Code:
[indent=0]
----
./gradlew cleanEclipse eclipse
----
If you have not built the project yet, run `./gradlew publishToMavenLocal` first so dependencies are resolved.
*VS Code:* Open the repository root as a folder. The repository includes `.vscode/settings.json` which disables automatic Gradle import so that the generated Eclipse metadata (`.classpath`, `.project`) is used. Do not use the Gradle for Java extension to import the project.
*Eclipse:* File → Import → General → Existing Projects into Workspace, then select the repository root.
The build uses a custom Eclipse plugin to work around Gradle dependency cycles that confuse IDE metadata generation. You may see Eclipse warnings about `xml-apis` from some test dependencies; those are excluded in the build and can be ignored.
See also the https://github.com/spring-projects/spring-framework/wiki/Gradle-build-and-release-FAQ[Gradle build and release FAQ].
== Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/support[Commercial support] is available too.
https://spring.io/services[Commercial support] is available too.
== Contributing
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details.
https://help.github.com/send-pull-requests[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md[contributor guidelines] for details.
== License
Spring Security is Open Source software released under the
-266
View File
@@ -1,266 +0,0 @@
= Release Process
The release process for Spring Security is entirely automated via the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc[Spring Security Release Plugin] and https://github.com/spring-io/spring-security-release-tools/tree/main/.github/workflows[reusable workflows].
The following table outlines the steps that are taken by the automation.
WARNING: The `5.8.x` branch does not have all of the improvements from the `6.x.x` branches. See "Status (5.8.x)" for which steps are still manual.
In case of a failure, you can follow the links below to read about each step, which includes instructions for performing the step manually if applicable.
See <<frequently-asked-questions,FAQ>> for troubleshooting tips.
[cols="1,1,1"]
|===
| Step | Status (5.8.x) | Status (6.0.x+)
| <<update-dependencies>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<check-all-issues-are-closed>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-release-version>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<tag-release>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<push-release-commit>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<build-locally>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-release-notes-on-github>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-version-on-project-page>>
| :x: manual
| :white_check_mark: automated
| <<close-create-milestone,Close milestone>>
| :x: manual
| :white_check_mark: automated
| <<announce-release-on-slack>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<update-to-next-development-version>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<close-create-milestone,Create milestone>>
| :white_check_mark: automated
| :white_check_mark: automated
| <<announce-release-on-other-channels>>
| :x: manual
| :x: manual
|===
[#update-dependencies]
== Update dependencies
Dependency versions are managed in the file xref:./gradle/libs.versions.toml[libs.versions.toml] and are automatically updated by xref:./.github/dependabot.yml[dependabot].
[#check-all-issues-are-closed]
== Check all issues are closed
The first step of a release is to check if there are any open issues remaining in a milestone.
NOTE: A scheduled release will not proceed if there are any open issues.
TIP: If you need to prevent a release from occurring automatically, the easiest way to block a release is to add an unresolved issue to the milestone.
The https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#checkMilestoneHasNoOpenIssues[`checkMilestoneHasOpenIssues`] command will check if there are any open issues for the release.
Before running the command manually, replace the following values:
* `<next-version>` - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`. This is optional since you are unlikely to reach the rate limit for such a simple check.
[source,bash]
----
./gradlew checkMilestoneHasOpenIssues -PnextVersion=<next-version> -PgitHubAccessToken=<github-personal-access-token>
----
Alternatively, you can manually check using the https://github.com/spring-projects/spring-security/milestones[milestones] page.
[#update-release-version]
== Update release version
If all issues for the release are <<check-all-issues-are-closed,closed>>, the version number is automatically updated using the milestone title.
When performing this step manually, update the version number in `gradle.properties` for the release (for example `5.5.0`) and commit the change using the message "Release x.y.z".
[#tag-release]
== Tag release
The release will automatically be tagged using the milestone title.
It is not required to tag manually.
However, you can perform this step manually by running the following command:
[source,bash]
----
git tag 5.5.0
----
[#push-release-commit]
== Push release commit
During a scheduled release, the release commit will automatically be pushed to trigger a build.
If performing this step manually, you can push the commit and tag and GitHub actions will build and deploy the artifacts with the following command:
[source,bash]
----
git push --atomic origin main 5.5.0
----
The build will automatically wait for artifacts to be released to Maven Central.
You can get notified manually when uploading is complete by running the following:
[source,bash]
----
./scripts/release/wait-for-done.sh 5.5.0
----
[#build-locally]
== Build
All checks will automatically be performed by the build prior to uploading the artifacts to Maven Central.
If something goes wrong, you can run the build locally using:
[source,bash]
----
./gradlew check
----
[#update-release-notes-on-github]
== Update release notes on GitHub
Once the release has been uploaded to Maven Central, release notes will automatically be generated and a GitHub release will be created.
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#generateChangelog[`generateChangelog`] command to generate the release notes by replacing:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
[source,bash]
----
./gradlew generateChangelog -PnextVersion=<next-version>
----
Then copy the release notes to your clipboard (your mileage may vary with the following command):
[source,bash]
----
cat build/changelog/release-notes.md | xclip -selection clipboard
----
Finally, create the
https://github.com/spring-projects/spring-security/releases[release on
GitHub], associate it with the tag, and paste the generated notes.
Alternatively, you can run the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createGitHubRelease[`createGitHubRelease`] command to perform these steps automatically, replacing:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
* `<branch>` - The name of the branch to be tagged (if the release commit has not already been tagged)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `write:org`
[source,bash]
----
./gradlew createGitHubRelease -PnextVersion=<next-version> -Pbranch=<branch> -PcreateRelease=true -PgitHubAccessToken=<github-personal-access-token>
----
[#update-version-on-project-page]
== Update version on project page
The build will automatically update the project versions on https://spring.io/projects/spring-security#learn.
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createSaganRelease[`createSaganRelease`] and https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#deleteSaganRelease[`deleteSaganRelease`] commands using the following parameters:
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
* `<previous-version>` - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-RC1)
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
[source,bash]
----
./gradlew createSaganRelease deleteSaganRelease -PnextVersion=<next-version> -PpreviousVersion=<previous-version> -PgitHubAccessToken=<github-personal-access-token>
----
Alternatively, you can log into Contentful and update the versions manually on the Spring Security project page.
[#close-create-milestone]
== Close / Create milestone
The release milestone will be automatically closed once the release is complete.
To proceed manually, perform the following steps:
1. Visit https://github.com/spring-projects/spring-security/milestones[GitHub
Milestones] and create a new milestone for the next release version
2. Move any open issues from the existing milestone you just released to the new milestone
3. Close the milestone for the release
NOTE: Remember that scheduled releases <<check-all-issues-are-closed,will not proceed>> if there are still open issues in the milestone.
[#announce-release-on-slack]
== Announce release on Slack
The release will automatically be announced on Slack.
If proceeding manually, announce the release on Slack in the channel https://pivotal.slack.com/messages/spring-release[#spring-release], including the keyword `+spring-security-announcing+` in the message.
Something like:
....
spring-security-announcing `5.5.0` is available now
....
[#update-to-next-development-version]
== Update to next development version
After the release is complete and artifacts have been uploaded to Maven Central, the build will automatically update to the next development version, commit and push.
If proceeding manually, update the version in `gradle.properties` to the next `+SNAPSHOT+` version with the commit message "Next development version" and then push.
[#announce-release-on-other-channels]
== Announce release on other channels
* Create a blog post on Contentful
* Tweet from https://twitter.com/springsecurity[@SpringSecurity]
[[frequently-asked-questions]]
== Frequently Asked Questions
*When should I update dependencies manually?* Dependencies should be updated at the latest the end of the week prior to the release. This is usually the Friday following the 2nd Monday of the month (counting from the first week with a Monday). When in doubt, check the https://github.com/spring-projects/spring-security/milestones[milestones] page for release due dates.
*When do scheduled releases occur?* Automated releases are scheduled to occur at *3:15 PM UTC* on the *3rd Monday of the month* (counting from the first week with a Monday).
[NOTE]
The scheduled release process currently runs every Monday but only releases when a release is due. See the performed checks below for more information.
The automated release process occurs on the following branches:
* `main`
* `6.2.x`
* `6.1.x`
* `6.0.x` (commercial only)
* `5.8.x`
For each of the above branches, the automated process performs the following checks before proceeding with the release:
1. _Check if the milestone is due today._ This check compares the current (SNAPSHOT) version of the branch with available milestones and chooses the first match (sorted alphabetically). If the due date on the matched milestone is *not* today, the process stops.
2. _Check if all issues are closed._ This check uses the milestone from the previous step and looks for open issues. If any open issues are found, the process stops.
[IMPORTANT]
You should ensure all issues are closed or moved to another milestone prior to a scheduled release.
If the above checks pass, the version number is updated (in `gradle.properties`) and a commit is pushed to trigger the CI process.
*How do I trigger a release manually?* You can trigger a release manually in two ways:
1. Trigger a release for a particular branch via https://github.com/spring-projects/spring-security/actions/workflows/update-scheduled-release-version.yml[`update-scheduled-release-version.yml`] on the desired branch. The above checks are performed for that branch, and the release will proceed if all checks pass. _This is the recommended way to trigger a release that did not pass the above checks during a regularly scheduled release._
2. Trigger releases for all branches via https://github.com/spring-projects/spring-security/actions/workflows/release-scheduler.yml[`release-scheduler.yml`] on the `main` branch. The above checks are performed for each branch, and only releases that pass all checks will proceed.
*When should additional manual steps be performed?* All other automated steps listed above occur during the normal CI process. Additional manual steps can be performed at any time once the builds pass and releases are finished.
*What if something goes wrong?* If the normal CI process fails, you can retry by re-running the failed jobs with the "Re-run failed jobs" option in GitHub Actions. If changes are required, you should revert the "Release x.y.z" commit, delete the tag, and proceed manually.
-54
View File
@@ -1,54 +0,0 @@
plugins {
id 'compile-warnings-error'
id 'javadoc-warnings-error'
}
apply plugin: 'io.spring.convention.spring-module'
dependencies {
management platform(project(":spring-security-dependencies"))
api project(':spring-security-crypto')
api project(':spring-security-core')
api 'org.springframework:spring-aop'
api 'org.springframework:spring-beans'
api 'org.springframework:spring-context'
api 'org.springframework:spring-core'
api 'org.springframework:spring-expression'
api 'io.micrometer:micrometer-observation'
optional project(':spring-security-acl')
optional project(':spring-security-messaging')
optional project(':spring-security-web')
optional 'org.springframework:spring-websocket'
optional 'com.fasterxml.jackson.core:jackson-databind'
optional 'io.micrometer:context-propagation'
optional 'io.projectreactor:reactor-core'
optional 'jakarta.annotation:jakarta.annotation-api'
optional 'org.aspectj:aspectjrt'
optional 'org.springframework:spring-jdbc'
optional 'org.springframework:spring-tx'
optional 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor'
provided 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(path : ':spring-security-web', configuration : 'tests')
testImplementation 'commons-collections:commons-collections'
testImplementation 'io.projectreactor:reactor-test'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"
testImplementation "org.junit.jupiter:junit-jupiter-engine"
testImplementation "org.mockito:mockito-core"
testImplementation "org.mockito:mockito-junit-jupiter"
testImplementation "org.springframework:spring-core-test"
testImplementation "org.springframework:spring-test"
testImplementation 'org.skyscreamer:jsonassert'
testImplementation 'org.springframework:spring-test'
testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation 'io.mockk:mockk'
testRuntimeOnly 'org.hsqldb:hsqldb'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
@@ -1,90 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Stores a {@link ConfigAttribute} as a <code>String</code>.
*
* @author Ben Alex
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. In the case of
* method security, please see {@link SecurityAnnotationScanner} and
* {@link AuthorizationManager}. In the case of channel security, please see
* {@code HttpsRedirectFilter}. In the case of web security, please see
* {@link AuthorizationManager}.
*/
@Deprecated
public class SecurityConfig implements ConfigAttribute {
@Serial
private static final long serialVersionUID = -7138084564199804304L;
private final String attrib;
public SecurityConfig(String config) {
Assert.hasText(config, "You must provide a configuration attribute");
this.attrib = config;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj instanceof ConfigAttribute attr) {
return this.attrib.equals(attr.getAttribute());
}
return false;
}
@Override
public String getAttribute() {
return this.attrib;
}
@Override
public int hashCode() {
return this.attrib.hashCode();
}
@Override
public String toString() {
return this.attrib;
}
public static List<ConfigAttribute> createListFromCommaDelimitedString(String access) {
return createList(StringUtils.commaDelimitedListToStringArray(access));
}
public static List<ConfigAttribute> createList(String... attributeNames) {
Assert.notNull(attributeNames, "You must supply an array of attribute names");
List<ConfigAttribute> attributes = new ArrayList<>(attributeNames.length);
for (String attribute : attributeNames) {
attributes.add(new SecurityConfig(attribute.trim()));
}
return attributes;
}
}
@@ -1,121 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource;
import org.springframework.util.StringUtils;
/**
* Sources method security metadata from major JSR 250 security annotations.
*
* @author Ben Alex
* @since 2.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.Jsr250AuthorizationManager}
* instead
*/
@NullUnmarked
@Deprecated
public class Jsr250MethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
private String defaultRolePrefix = "ROLE_";
/**
* <p>
* Sets the default prefix to be added to {@link RolesAllowed}. For example, if
* {@code @RolesAllowed("ADMIN")} or {@code @RolesAllowed("ADMIN")} is used, then the
* role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
* </p>
*
* <p>
* If null or empty, then no default role prefix is used.
* </p>
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
*/
public void setDefaultRolePrefix(String defaultRolePrefix) {
this.defaultRolePrefix = defaultRolePrefix;
}
@Override
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
return processAnnotations(clazz.getAnnotations());
}
@Override
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
return processAnnotations(AnnotationUtils.getAnnotations(method));
}
@Override
public @Nullable Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
private @Nullable List<ConfigAttribute> processAnnotations(Annotation @Nullable [] annotations) {
if (annotations == null || annotations.length == 0) {
return null;
}
List<ConfigAttribute> attributes = new ArrayList<>();
for (Annotation annotation : annotations) {
if (annotation instanceof DenyAll) {
attributes.add(Jsr250SecurityConfig.DENY_ALL_ATTRIBUTE);
return attributes;
}
if (annotation instanceof PermitAll) {
attributes.add(Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE);
return attributes;
}
if (annotation instanceof RolesAllowed ra) {
for (String allowed : ra.value()) {
String defaultedAllowed = getRoleWithDefaultPrefix(allowed);
attributes.add(new Jsr250SecurityConfig(defaultedAllowed));
}
return attributes;
}
}
return null;
}
private String getRoleWithDefaultPrefix(String role) {
if (role == null) {
return role;
}
if (!StringUtils.hasLength(this.defaultRolePrefix)) {
return role;
}
if (role.startsWith(this.defaultRolePrefix)) {
return role;
}
return this.defaultRolePrefix + role;
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.annotation;
import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.PermitAll;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
/**
* Security config applicable as a JSR 250 annotation attribute.
*
* @author Ryan Heaton
* @since 2.0
* @deprecated Use {@link AuthorizationManagerBeforeMethodInterceptor#jsr250()} instead
*/
@Deprecated
@SuppressWarnings("serial")
public class Jsr250SecurityConfig extends SecurityConfig {
public static final Jsr250SecurityConfig PERMIT_ALL_ATTRIBUTE = new Jsr250SecurityConfig(PermitAll.class.getName());
public static final Jsr250SecurityConfig DENY_ALL_ATTRIBUTE = new Jsr250SecurityConfig(DenyAll.class.getName());
public Jsr250SecurityConfig(String role) {
super(role);
}
}
@@ -1,102 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource;
import org.springframework.util.Assert;
/**
* Sources method security metadata from Spring Security's {@link Secured} annotation.
* <p>
* Can also be used with custom security annotations by injecting an
* {@link AnnotationMetadataExtractor}. The annotation type will then be obtained from the
* generic parameter type supplied to this interface
*
* @author Ben Alex
* @author Luke Taylor
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor#secured}
*/
@NullUnmarked
@Deprecated
@SuppressWarnings({ "unchecked" })
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
private AnnotationMetadataExtractor annotationExtractor;
private @Nullable Class<? extends Annotation> annotationType;
public SecuredAnnotationSecurityMetadataSource() {
this(new SecuredAnnotationMetadataExtractor());
}
public SecuredAnnotationSecurityMetadataSource(AnnotationMetadataExtractor annotationMetadataExtractor) {
Assert.notNull(annotationMetadataExtractor, "annotationMetadataExtractor cannot be null");
this.annotationExtractor = annotationMetadataExtractor;
this.annotationType = (Class<? extends Annotation>) GenericTypeResolver
.resolveTypeArgument(this.annotationExtractor.getClass(), AnnotationMetadataExtractor.class);
Assert.notNull(this.annotationType, () -> this.annotationExtractor.getClass().getName()
+ " must supply a generic parameter for AnnotationMetadataExtractor");
}
@Override
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
return processAnnotation(AnnotationUtils.findAnnotation(clazz, this.annotationType));
}
@Override
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
return processAnnotation(AnnotationUtils.findAnnotation(method, this.annotationType));
}
@Override
public @Nullable Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
private @Nullable Collection<ConfigAttribute> processAnnotation(@Nullable Annotation annotation) {
return (annotation != null) ? this.annotationExtractor.extractAttributes(annotation) : null;
}
static class SecuredAnnotationMetadataExtractor implements AnnotationMetadataExtractor<Secured> {
@Override
public Collection<ConfigAttribute> extractAttributes(Secured secured) {
String[] attributeTokens = secured.value();
List<ConfigAttribute> attributes = new ArrayList<>(attributeTokens.length);
for (String token : attributeTokens) {
attributes.add(new SecurityConfig(token));
}
return attributes;
}
}
}
@@ -1,67 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.event;
import java.util.Collection;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.util.Assert;
/**
* Indicates a secure object invocation failed because the <code>Authentication</code>
* could not be obtained from the <code>SecurityContextHolder</code>.
*
* @author Ben Alex
* @deprecated Authentication is now separated from authorization. Consider
* {@link org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent}
* instead.
*/
@Deprecated
@SuppressWarnings("serial")
public class AuthenticationCredentialsNotFoundEvent extends AbstractAuthorizationEvent {
private final AuthenticationCredentialsNotFoundException credentialsNotFoundException;
private final Collection<ConfigAttribute> configAttribs;
/**
* Construct the event.
* @param secureObject the secure object
* @param attributes that apply to the secure object
* @param credentialsNotFoundException exception returned to the caller (contains
* reason)
*
*/
public AuthenticationCredentialsNotFoundEvent(Object secureObject, Collection<ConfigAttribute> attributes,
AuthenticationCredentialsNotFoundException credentialsNotFoundException) {
super(secureObject);
Assert.isTrue(attributes != null && credentialsNotFoundException != null,
"All parameters are required and cannot be null");
this.configAttribs = attributes;
this.credentialsNotFoundException = credentialsNotFoundException;
}
public Collection<ConfigAttribute> getConfigAttributes() {
return this.configAttribs;
}
public AuthenticationCredentialsNotFoundException getCredentialsNotFoundException() {
return this.credentialsNotFoundException;
}
}
@@ -1,82 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.event;
import java.util.Collection;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Indicates a secure object invocation failed because the principal could not be
* authorized for the request.
*
* <p>
* This event might be thrown as a result of either an
* {@link org.springframework.security.access.AccessDecisionManager AccessDecisionManager}
* or an {@link org.springframework.security.access.intercept.AfterInvocationManager
* AfterInvocationManager}.
*
* @author Ben Alex
* @deprecated Use
* {@link org.springframework.security.authorization.event.AuthorizationDeniedEvent}
* instead
*/
@Deprecated
@SuppressWarnings("serial")
public class AuthorizationFailureEvent extends AbstractAuthorizationEvent {
private final AccessDeniedException accessDeniedException;
private final Authentication authentication;
private final Collection<ConfigAttribute> configAttributes;
/**
* Construct the event.
* @param secureObject the secure object
* @param attributes that apply to the secure object
* @param authentication that was found in the <code>SecurityContextHolder</code>
* @param accessDeniedException that was returned by the
* <code>AccessDecisionManager</code>
* @throws IllegalArgumentException if any null arguments are presented.
*/
public AuthorizationFailureEvent(Object secureObject, Collection<ConfigAttribute> attributes,
Authentication authentication, AccessDeniedException accessDeniedException) {
super(secureObject);
Assert.isTrue(attributes != null && authentication != null && accessDeniedException != null,
"All parameters are required and cannot be null");
this.configAttributes = attributes;
this.authentication = authentication;
this.accessDeniedException = accessDeniedException;
}
public AccessDeniedException getAccessDeniedException() {
return this.accessDeniedException;
}
public Authentication getAuthentication() {
return this.authentication;
}
public Collection<ConfigAttribute> getConfigAttributes() {
return this.configAttributes;
}
}
@@ -1,66 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.event;
import java.util.Collection;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Event indicating a secure object was invoked successfully.
* <P>
* Published just before the secure object attempts to proceed.
* </p>
*
* @author Ben Alex
* @deprecated Use
* {@link org.springframework.security.authorization.event.AuthorizationGrantedEvent}
* instead
*/
@Deprecated
@SuppressWarnings("serial")
public class AuthorizedEvent extends AbstractAuthorizationEvent {
private final Authentication authentication;
private final Collection<ConfigAttribute> configAttributes;
/**
* Construct the event.
* @param secureObject the secure object
* @param attributes that apply to the secure object
* @param authentication that successfully called the secure object
*
*/
public AuthorizedEvent(Object secureObject, Collection<ConfigAttribute> attributes, Authentication authentication) {
super(secureObject);
Assert.isTrue(attributes != null && authentication != null, "All parameters are required and cannot be null");
this.configAttributes = attributes;
this.authentication = authentication;
}
public Authentication getAuthentication() {
return this.authentication;
}
public Collection<ConfigAttribute> getConfigAttributes() {
return this.configAttributes;
}
}
@@ -1,81 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.core.log.LogMessage;
/**
* Outputs interceptor-related application events to Commons Logging.
* <p>
* All failures are logged at the warning level, with success events logged at the
* information level, and public invocation events logged at the debug level.
* </p>
*
* @author Ben Alex
* @deprecated Logging is now embedded in Spring Security components. If you need further
* logging, please consider using your own {@link ApplicationListener}
*/
@Deprecated
public class LoggerListener implements ApplicationListener<AbstractAuthorizationEvent> {
private static final Log logger = LogFactory.getLog(LoggerListener.class);
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
if (event instanceof AuthenticationCredentialsNotFoundEvent) {
onAuthenticationCredentialsNotFoundEvent((AuthenticationCredentialsNotFoundEvent) event);
}
if (event instanceof AuthorizationFailureEvent) {
onAuthorizationFailureEvent((AuthorizationFailureEvent) event);
}
if (event instanceof AuthorizedEvent) {
onAuthorizedEvent((AuthorizedEvent) event);
}
if (event instanceof PublicInvocationEvent) {
onPublicInvocationEvent((PublicInvocationEvent) event);
}
}
private void onAuthenticationCredentialsNotFoundEvent(AuthenticationCredentialsNotFoundEvent authEvent) {
logger.warn(LogMessage.format(
"Security interception failed due to: %s; secure object: %s; configuration attributes: %s",
authEvent.getCredentialsNotFoundException(), authEvent.getSource(), authEvent.getConfigAttributes()));
}
private void onPublicInvocationEvent(PublicInvocationEvent event) {
logger.info(LogMessage.format("Security interception not required for public secure object: %s",
event.getSource()));
}
private void onAuthorizedEvent(AuthorizedEvent authEvent) {
logger.info(LogMessage.format(
"Security authorized for authenticated principal: %s; secure object: %s; configuration attributes: %s",
authEvent.getAuthentication(), authEvent.getSource(), authEvent.getConfigAttributes()));
}
private void onAuthorizationFailureEvent(AuthorizationFailureEvent authEvent) {
logger.warn(LogMessage.format(
"Security authorization failed due to: %s; authenticated principal: %s; secure object: %s; configuration attributes: %s",
authEvent.getAccessDeniedException(), authEvent.getAuthentication(), authEvent.getSource(),
authEvent.getConfigAttributes()));
}
}
@@ -1,23 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Authorization event and listener classes.
*/
@NullMarked
package org.springframework.security.access.event;
import org.jspecify.annotations.NullMarked;
@@ -1,82 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.Assert;
/**
* Contains both filtering and authorization expression meta-data for Spring-EL based
* access control.
* <p>
* Base class for pre or post-invocation phases of a method invocation.
* <p>
* Either filter or authorization expressions may be null, but not both.
*
* @author Luke Taylor
* @since 3.0
* @deprecated Use {@link org.springframework.security.authorization.AuthorizationManager}
* interceptors instead
*/
@NullUnmarked
@Deprecated
abstract class AbstractExpressionBasedMethodConfigAttribute implements ConfigAttribute {
private final @Nullable Expression filterExpression;
private final @Nullable Expression authorizeExpression;
/**
* Parses the supplied expressions as Spring-EL.
*/
AbstractExpressionBasedMethodConfigAttribute(String filterExpression, String authorizeExpression)
throws ParseException {
Assert.isTrue(filterExpression != null || authorizeExpression != null,
"Filter and authorization Expressions cannot both be null");
SpelExpressionParser parser = new SpelExpressionParser();
this.filterExpression = (filterExpression != null) ? parser.parseExpression(filterExpression) : null;
this.authorizeExpression = (authorizeExpression != null) ? parser.parseExpression(authorizeExpression) : null;
}
AbstractExpressionBasedMethodConfigAttribute(Expression filterExpression, Expression authorizeExpression)
throws ParseException {
Assert.isTrue(filterExpression != null || authorizeExpression != null,
"Filter and authorization Expressions cannot both be null");
this.filterExpression = (filterExpression != null) ? filterExpression : null;
this.authorizeExpression = (authorizeExpression != null) ? authorizeExpression : null;
}
Expression getFilterExpression() {
return this.filterExpression;
}
Expression getAuthorizeExpression() {
return this.authorizeExpression;
}
@Override
public @Nullable String getAttribute() {
return null;
}
}
@@ -1,107 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PrePostInvocationAttributeFactory;
import org.springframework.util.Assert;
/**
* {@link PrePostInvocationAttributeFactory} which interprets the annotation value as an
* expression to be evaluated at runtime.
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.0
* @deprecated Use {@link org.springframework.security.authorization.AuthorizationManager}
* interceptors instead
*/
@NullUnmarked
@Deprecated
public class ExpressionBasedAnnotationAttributeFactory implements PrePostInvocationAttributeFactory {
private final Object parserLock = new Object();
private @Nullable ExpressionParser parser;
private MethodSecurityExpressionHandler handler;
public ExpressionBasedAnnotationAttributeFactory(MethodSecurityExpressionHandler handler) {
Assert.notNull(handler, "handler cannot be null");
this.handler = handler;
}
@Override
public PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute, String filterObject,
String preAuthorizeAttribute) {
try {
// TODO: Optimization of permitAll
ExpressionParser parser = getParser();
Expression preAuthorizeExpression = (preAuthorizeAttribute != null)
? parser.parseExpression(preAuthorizeAttribute) : parser.parseExpression("permitAll");
Expression preFilterExpression = (preFilterAttribute != null) ? parser.parseExpression(preFilterAttribute)
: null;
return new PreInvocationExpressionAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
}
catch (ParseException ex) {
throw new IllegalArgumentException("Failed to parse expression '" + ex.getExpressionString() + "'", ex);
}
}
@Override
public @Nullable PostInvocationAttribute createPostInvocationAttribute(String postFilterAttribute,
String postAuthorizeAttribute) {
try {
ExpressionParser parser = getParser();
Expression postAuthorizeExpression = (postAuthorizeAttribute != null)
? parser.parseExpression(postAuthorizeAttribute) : null;
Expression postFilterExpression = (postFilterAttribute != null)
? parser.parseExpression(postFilterAttribute) : null;
if (postFilterExpression != null || postAuthorizeExpression != null) {
return new PostInvocationExpressionAttribute(postFilterExpression, postAuthorizeExpression);
}
}
catch (ParseException ex) {
throw new IllegalArgumentException("Failed to parse expression '" + ex.getExpressionString() + "'", ex);
}
return null;
}
/**
* Delay the lookup of the {@link ExpressionParser} to prevent SEC-2136
* @return
*/
private ExpressionParser getParser() {
if (this.parser != null) {
return this.parser;
}
synchronized (this.parserLock) {
this.parser = this.handler.getExpressionParser();
this.handler = null;
}
return this.parser;
}
}
@@ -1,74 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PostInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
/**
* @author Luke Taylor
* @since 3.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor}
* instead
*/
@Deprecated
public class ExpressionBasedPostInvocationAdvice implements PostInvocationAuthorizationAdvice {
protected final Log logger = LogFactory.getLog(getClass());
private final MethodSecurityExpressionHandler expressionHandler;
public ExpressionBasedPostInvocationAdvice(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;
}
@Override
public Object after(Authentication authentication, MethodInvocation mi, PostInvocationAttribute postAttr,
Object returnedObject) throws AccessDeniedException {
PostInvocationExpressionAttribute pia = (PostInvocationExpressionAttribute) postAttr;
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, mi);
Expression postFilter = pia.getFilterExpression();
Expression postAuthorize = pia.getAuthorizeExpression();
if (postFilter != null) {
this.logger.debug(LogMessage.format("Applying PostFilter expression %s", postFilter));
if (returnedObject != null) {
returnedObject = this.expressionHandler.filter(returnedObject, postFilter, ctx);
}
else {
this.logger.debug("Return object is null, filtering will be skipped");
}
}
this.expressionHandler.setReturnObject(returnedObject, ctx);
if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
this.logger.debug("PostAuthorize expression rejected access");
throw new AccessDeniedException("Access is denied");
}
return returnedObject;
}
}
@@ -1,88 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import java.util.Collection;
import org.aopalliance.intercept.MethodInvocation;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Method pre-invocation handling based on expressions.
*
* @author Luke Taylor
* @since 3.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor}
* instead
*/
@NullUnmarked
@Deprecated
public class ExpressionBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice {
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
@Override
public boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute attr) {
PreInvocationExpressionAttribute preAttr = (PreInvocationExpressionAttribute) attr;
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, mi);
Expression preFilter = preAttr.getFilterExpression();
Expression preAuthorize = preAttr.getAuthorizeExpression();
if (preFilter != null) {
Object filterTarget = findFilterTarget(preAttr.getFilterTarget(), ctx, mi);
this.expressionHandler.filter(filterTarget, preFilter, ctx);
}
return (preAuthorize != null) ? ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx) : true;
}
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation invocation) {
Object filterTarget = null;
if (filterTargetName.length() > 0) {
filterTarget = ctx.lookupVariable(filterTargetName);
Assert.notNull(filterTarget,
() -> "Filter target was null, or no argument with name " + filterTargetName + " found in method");
}
else if (invocation.getArguments().length == 1) {
Object arg = invocation.getArguments()[0];
if (arg.getClass().isArray() || arg instanceof Collection<?>) {
filterTarget = arg;
}
Assert.notNull(filterTarget, () -> "A PreFilter expression was set but the method argument type"
+ arg.getClass() + " is not filterable");
}
else if (invocation.getArguments().length > 1) {
throw new IllegalArgumentException(
"Unable to determine the method argument for filtering. Specify the filter target.");
}
Assert.isTrue(!filterTarget.getClass().isArray(),
"Pre-filtering on array types is not supported. Using a Collection will solve this problem");
return filterTarget;
}
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;
}
}
@@ -1,56 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PostInvocationAttribute;
/**
* @author Luke Taylor
* @since 3.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor}
* instead
*/
@Deprecated
@SuppressWarnings("serial")
class PostInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
implements PostInvocationAttribute {
PostInvocationExpressionAttribute(String filterExpression, String authorizeExpression) throws ParseException {
super(filterExpression, authorizeExpression);
}
PostInvocationExpressionAttribute(@Nullable Expression filterExpression, @Nullable Expression authorizeExpression)
throws ParseException {
super(filterExpression, authorizeExpression);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expression authorize = getAuthorizeExpression();
Expression filter = getFilterExpression();
sb.append("[authorize: '").append((authorize != null) ? authorize.getExpressionString() : "null");
sb.append("', filter: '").append((filter != null) ? filter.getExpressionString() : "null").append("']");
return sb.toString();
}
}
@@ -1,71 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.expression.method;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PreInvocationAttribute;
/**
* @author Luke Taylor
* @since 3.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor}
* instead
*/
@Deprecated
@SuppressWarnings("serial")
class PreInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
implements PreInvocationAttribute {
private final String filterTarget;
PreInvocationExpressionAttribute(String filterExpression, String filterTarget, String authorizeExpression)
throws ParseException {
super(filterExpression, authorizeExpression);
this.filterTarget = filterTarget;
}
PreInvocationExpressionAttribute(@Nullable Expression filterExpression, String filterTarget,
Expression authorizeExpression) throws ParseException {
super(filterExpression, authorizeExpression);
this.filterTarget = filterTarget;
}
/**
* The parameter name of the target argument (must be a Collection) to which filtering
* will be applied.
* @return the method parameter name
*/
String getFilterTarget() {
return this.filterTarget;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expression authorize = getAuthorizeExpression();
Expression filter = getFilterExpression();
sb.append("[authorize: '").append((authorize != null) ? authorize.getExpressionString() : "null");
sb.append("', filter: '").append((filter != null) ? filter.getExpressionString() : "null");
sb.append("', filterTarget: '").append(this.filterTarget).append("']");
return sb.toString();
}
}
@@ -1,496 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.access.event.AuthorizedEvent;
import org.springframework.security.access.event.PublicInvocationEvent;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Abstract class that implements security interception for secure objects.
* <p>
* The <code>AbstractSecurityInterceptor</code> will ensure the proper startup
* configuration of the security interceptor. It will also implement the proper handling
* of secure object invocations, namely:
* <ol>
* <li>Obtain the {@link Authentication} object from the
* {@link SecurityContextHolder}.</li>
* <li>Determine if the request relates to a secured or public invocation by looking up
* the secure object request against the {@link SecurityMetadataSource}.</li>
* <li>For an invocation that is secured (there is a list of <code>ConfigAttribute</code>s
* for the secure object invocation):
* <ol type="a">
* <li>If either the
* {@link org.springframework.security.core.Authentication#isAuthenticated()} returns
* <code>false</code>, or the {@link #alwaysReauthenticate} is <code>true</code>,
* authenticate the request against the configured {@link AuthenticationManager}. When
* authenticated, replace the <code>Authentication</code> object on the
* <code>SecurityContextHolder</code> with the returned value.</li>
* <li>Authorize the request against the configured {@link AccessDecisionManager}.</li>
* <li>Perform any run-as replacement via the configured {@link RunAsManager}.</li>
* <li>Pass control back to the concrete subclass, which will actually proceed with
* executing the object. A {@link InterceptorStatusToken} is returned so that after the
* subclass has finished proceeding with execution of the object, its finally clause can
* ensure the <code>AbstractSecurityInterceptor</code> is re-called and tidies up
* correctly using {@link #finallyInvocation(InterceptorStatusToken)}.</li>
* <li>The concrete subclass will re-call the <code>AbstractSecurityInterceptor</code> via
* the {@link #afterInvocation(InterceptorStatusToken, Object)} method.</li>
* <li>If the <code>RunAsManager</code> replaced the <code>Authentication</code> object,
* return the <code>SecurityContextHolder</code> to the object that existed after the call
* to <code>AuthenticationManager</code>.</li>
* <li>If an <code>AfterInvocationManager</code> is defined, invoke the invocation manager
* and allow it to replace the object due to be returned to the caller.</li>
* </ol>
* </li>
* <li>For an invocation that is public (there are no <code>ConfigAttribute</code>s for
* the secure object invocation):
* <ol type="a">
* <li>As described above, the concrete subclass will be returned an
* <code>InterceptorStatusToken</code> which is subsequently re-presented to the
* <code>AbstractSecurityInterceptor</code> after the secure object has been executed. The
* <code>AbstractSecurityInterceptor</code> will take no further action when its
* {@link #afterInvocation(InterceptorStatusToken, Object)} is called.</li>
* </ol>
* </li>
* <li>Control again returns to the concrete subclass, along with the <code>Object</code>
* that should be returned to the caller. The subclass will then return that result or
* exception to the original caller.</li>
* </ol>
*
* @author Ben Alex
* @author Rob Winch
* @deprecated Use
* {@link org.springframework.security.web.access.intercept.AuthorizationFilter} instead
* for filter security,
* {@link org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor}
* for messaging security, or
* {@link org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor}
* and
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor}
* for method security.
*/
@NullUnmarked
@Deprecated
public abstract class AbstractSecurityInterceptor
implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware {
protected final Log logger = LogFactory.getLog(getClass());
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private @Nullable ApplicationEventPublisher eventPublisher;
private @Nullable AccessDecisionManager accessDecisionManager;
private @Nullable AfterInvocationManager afterInvocationManager;
private AuthenticationManager authenticationManager = new NoOpAuthenticationManager();
private RunAsManager runAsManager = new NullRunAsManager();
private boolean alwaysReauthenticate = false;
private boolean rejectPublicInvocations = false;
private boolean validateConfigAttributes = true;
private boolean publishAuthorizationSuccess = false;
@Override
public void afterPropertiesSet() {
Assert.notNull(getSecureObjectClass(), "Subclass must provide a non-null response to getSecureObjectClass()");
Assert.notNull(this.messages, "A message source must be set");
Assert.notNull(this.authenticationManager, "An AuthenticationManager is required");
Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required");
Assert.notNull(this.runAsManager, "A RunAsManager is required");
Assert.notNull(this.obtainSecurityMetadataSource(), "An SecurityMetadataSource is required");
Assert.isTrue(this.obtainSecurityMetadataSource().supports(getSecureObjectClass()),
() -> "SecurityMetadataSource does not support secure object class: " + getSecureObjectClass());
Assert.isTrue(this.runAsManager.supports(getSecureObjectClass()),
() -> "RunAsManager does not support secure object class: " + getSecureObjectClass());
Assert.isTrue(this.accessDecisionManager.supports(getSecureObjectClass()),
() -> "AccessDecisionManager does not support secure object class: " + getSecureObjectClass());
if (this.afterInvocationManager != null) {
Assert.isTrue(this.afterInvocationManager.supports(getSecureObjectClass()),
() -> "AfterInvocationManager does not support secure object class: " + getSecureObjectClass());
}
if (this.validateConfigAttributes) {
Collection<ConfigAttribute> attributeDefs = this.obtainSecurityMetadataSource().getAllConfigAttributes();
if (attributeDefs == null) {
this.logger.warn("Could not validate configuration attributes as the "
+ "SecurityMetadataSource did not return any attributes from getAllConfigAttributes()");
return;
}
validateAttributeDefs(attributeDefs);
}
}
private void validateAttributeDefs(Collection<ConfigAttribute> attributeDefs) {
Set<ConfigAttribute> unsupportedAttrs = new HashSet<>();
for (ConfigAttribute attr : attributeDefs) {
if (!this.runAsManager.supports(attr) && !this.accessDecisionManager.supports(attr)
&& ((this.afterInvocationManager == null) || !this.afterInvocationManager.supports(attr))) {
unsupportedAttrs.add(attr);
}
}
if (unsupportedAttrs.size() != 0) {
this.logger
.trace("Did not validate configuration attributes since validateConfigurationAttributes is false");
throw new IllegalArgumentException("Unsupported configuration attributes: " + unsupportedAttrs);
}
else {
this.logger.trace("Validated configuration attributes");
}
}
protected @Nullable InterceptorStatusToken beforeInvocation(Object object) {
Assert.notNull(object, "Object was null");
if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
throw new IllegalArgumentException("Security invocation attempted for object " + object.getClass().getName()
+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
+ getSecureObjectClass());
}
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
if (CollectionUtils.isEmpty(attributes)) {
Assert.isTrue(!this.rejectPublicInvocations,
() -> "Secure object invocation " + object
+ " was denied as public invocations are not allowed via this interceptor. "
+ "This indicates a configuration error because the "
+ "rejectPublicInvocations property is set to 'true'");
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Authorized public object %s", object));
}
publishEvent(new PublicInvocationEvent(object));
return null; // no further work post-invocation
}
if (this.securityContextHolderStrategy.getContext().getAuthentication() == null) {
credentialsNotFound(this.messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",
"An Authentication object was not found in the SecurityContext"), object, attributes);
}
Authentication authenticated = authenticateIfRequired();
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Authorizing %s with attributes %s", object, attributes));
}
// Attempt authorization
attemptAuthorization(object, attributes, authenticated);
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Authorized %s with attributes %s", object, attributes));
}
if (this.publishAuthorizationSuccess) {
publishEvent(new AuthorizedEvent(object, attributes, authenticated));
}
// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
if (runAs != null) {
SecurityContext origCtx = this.securityContextHolderStrategy.getContext();
SecurityContext newCtx = this.securityContextHolderStrategy.createEmptyContext();
newCtx.setAuthentication(runAs);
this.securityContextHolderStrategy.setContext(newCtx);
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Switched to RunAs authentication %s", runAs));
}
// need to revert to token.Authenticated post-invocation
return new InterceptorStatusToken(origCtx, true, attributes, object);
}
this.logger.trace("Did not switch RunAs authentication since RunAsManager returned null");
// no further work post-invocation
return new InterceptorStatusToken(this.securityContextHolderStrategy.getContext(), false, attributes, object);
}
private void attemptAuthorization(Object object, Collection<ConfigAttribute> attributes,
Authentication authenticated) {
try {
this.accessDecisionManager.decide(authenticated, object, attributes);
}
catch (AccessDeniedException ex) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Failed to authorize %s with attributes %s using %s", object,
attributes, this.accessDecisionManager));
}
else if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Failed to authorize %s with attributes %s", object, attributes));
}
publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, ex));
throw ex;
}
}
/**
* Cleans up the work of the <tt>AbstractSecurityInterceptor</tt> after the secure
* object invocation has been completed. This method should be invoked after the
* secure object invocation and before afterInvocation regardless of the secure object
* invocation returning successfully (i.e. it should be done in a finally block).
* @param token as returned by the {@link #beforeInvocation(Object)} method
*/
protected void finallyInvocation(InterceptorStatusToken token) {
if (token != null && token.isContextHolderRefreshRequired()) {
this.securityContextHolderStrategy.setContext(token.getSecurityContext());
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage
.of(() -> "Reverted to original authentication " + token.getSecurityContext().getAuthentication()));
}
}
}
/**
* Completes the work of the <tt>AbstractSecurityInterceptor</tt> after the secure
* object invocation has been completed.
* @param token as returned by the {@link #beforeInvocation(Object)} method
* @param returnedObject any object returned from the secure object invocation (may be
* <tt>null</tt>)
* @return the object the secure object invocation should ultimately return to its
* caller (may be <tt>null</tt>)
*/
protected Object afterInvocation(InterceptorStatusToken token, @Nullable Object returnedObject) {
if (token == null) {
// public object
return returnedObject;
}
finallyInvocation(token); // continue to clean in this method for passivity
if (this.afterInvocationManager != null) {
// Attempt after invocation handling
try {
returnedObject = this.afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
token.getSecureObject(), token.getAttributes(), returnedObject);
}
catch (AccessDeniedException ex) {
publishEvent(new AuthorizationFailureEvent(token.getSecureObject(), token.getAttributes(),
token.getSecurityContext().getAuthentication(), ex));
throw ex;
}
}
return returnedObject;
}
/**
* Checks the current authentication token and passes it to the AuthenticationManager
* if {@link org.springframework.security.core.Authentication#isAuthenticated()}
* returns false or the property <tt>alwaysReauthenticate</tt> has been set to true.
* @return an authenticated <tt>Authentication</tt> object.
*/
private Authentication authenticateIfRequired() {
Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
if (authentication.isAuthenticated() && !this.alwaysReauthenticate) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Did not re-authenticate %s before authorizing", authentication));
}
return authentication;
}
authentication = this.authenticationManager.authenticate(authentication);
// Don't authenticated.setAuthentication(true) because each provider does that
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Re-authenticated %s before authorizing", authentication));
}
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
context.setAuthentication(authentication);
this.securityContextHolderStrategy.setContext(context);
return authentication;
}
/**
* Helper method which generates an exception containing the passed reason, and
* publishes an event to the application context.
* <p>
* Always throws an exception.
* @param reason to be provided in the exception detail
* @param secureObject that was being called
* @param configAttribs that were defined for the secureObject
*/
private void credentialsNotFound(String reason, Object secureObject, Collection<ConfigAttribute> configAttribs) {
AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason);
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
configAttribs, exception);
publishEvent(event);
throw exception;
}
public AccessDecisionManager getAccessDecisionManager() {
return this.accessDecisionManager;
}
public AfterInvocationManager getAfterInvocationManager() {
return this.afterInvocationManager;
}
public AuthenticationManager getAuthenticationManager() {
return this.authenticationManager;
}
public RunAsManager getRunAsManager() {
return this.runAsManager;
}
/**
* Indicates the type of secure objects the subclass will be presenting to the
* abstract parent for processing. This is used to ensure collaborators wired to the
* {@code AbstractSecurityInterceptor} all support the indicated secure object class.
* @return the type of secure object the subclass provides services for
*/
public abstract Class<?> getSecureObjectClass();
public boolean isAlwaysReauthenticate() {
return this.alwaysReauthenticate;
}
public boolean isRejectPublicInvocations() {
return this.rejectPublicInvocations;
}
public boolean isValidateConfigAttributes() {
return this.validateConfigAttributes;
}
public abstract SecurityMetadataSource obtainSecurityMetadataSource();
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
}
public void setAfterInvocationManager(AfterInvocationManager afterInvocationManager) {
this.afterInvocationManager = afterInvocationManager;
}
/**
* Indicates whether the <code>AbstractSecurityInterceptor</code> should ignore the
* {@link Authentication#isAuthenticated()} property. Defaults to <code>false</code>,
* meaning by default the <code>Authentication.isAuthenticated()</code> property is
* trusted and re-authentication will not occur if the principal has already been
* authenticated.
* @param alwaysReauthenticate <code>true</code> to force
* <code>AbstractSecurityInterceptor</code> to disregard the value of
* <code>Authentication.isAuthenticated()</code> and always re-authenticate the
* request (defaults to <code>false</code>).
*/
public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
this.alwaysReauthenticate = alwaysReauthenticate;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public void setAuthenticationManager(AuthenticationManager newManager) {
this.authenticationManager = newManager;
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
/**
* Only {@code AuthorizationFailureEvent} will be published. If you set this property
* to {@code true}, {@code AuthorizedEvent}s will also be published.
* @param publishAuthorizationSuccess default value is {@code false}
*/
public void setPublishAuthorizationSuccess(boolean publishAuthorizationSuccess) {
this.publishAuthorizationSuccess = publishAuthorizationSuccess;
}
/**
* By rejecting public invocations (and setting this property to <tt>true</tt>),
* essentially you are ensuring that every secure object invocation advised by
* <code>AbstractSecurityInterceptor</code> has a configuration attribute defined.
* This is useful to ensure a "fail safe" mode where undeclared secure objects will be
* rejected and configuration omissions detected early. An
* <tt>IllegalArgumentException</tt> will be thrown by the
* <tt>AbstractSecurityInterceptor</tt> if you set this property to <tt>true</tt> and
* an attempt is made to invoke a secure object that has no configuration attributes.
* @param rejectPublicInvocations set to <code>true</code> to reject invocations of
* secure objects that have no configuration attributes (by default it is
* <code>false</code> which treats undeclared secure objects as "public" or
* unauthorized).
*/
public void setRejectPublicInvocations(boolean rejectPublicInvocations) {
this.rejectPublicInvocations = rejectPublicInvocations;
}
public void setRunAsManager(RunAsManager runAsManager) {
this.runAsManager = runAsManager;
}
public void setValidateConfigAttributes(boolean validateConfigAttributes) {
this.validateConfigAttributes = validateConfigAttributes;
}
private void publishEvent(ApplicationEvent event) {
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(event);
}
}
private static class NoOpAuthenticationManager implements AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
throw new AuthenticationServiceException("Cannot authenticate " + authentication);
}
}
}
@@ -1,131 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AfterInvocationProvider;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Provider-based implementation of {@link AfterInvocationManager}.
* <p>
* Handles configuration of a bean context defined list of {@link AfterInvocationProvider}
* s.
* <p>
* Every <code>AfterInvocationProvider</code> will be polled when the
* {@link #decide(Authentication, Object, Collection, Object)} method is called. The
* <code>Object</code> returned from each provider will be presented to the successive
* provider for processing. This means each provider <b>must</b> ensure they return the
* <code>Object</code>, even if they are not interested in the "after invocation" decision
* (perhaps as the secure object invocation did not include a configuration attribute a
* given provider is configured to respond to).
*
* @author Ben Alex
* @see org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor
* @see org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor
* @deprecated Use delegation with {@link AuthorizationManager}
*/
@NullUnmarked
@Deprecated
public class AfterInvocationProviderManager implements AfterInvocationManager, InitializingBean {
protected static final Log logger = LogFactory.getLog(AfterInvocationProviderManager.class);
@SuppressWarnings("NullAway.Init")
private @Nullable List<AfterInvocationProvider> providers;
@Override
public void afterPropertiesSet() {
checkIfValidList(this.providers);
}
@Override
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
Object result = returnedObject;
for (AfterInvocationProvider provider : this.providers) {
result = provider.decide(authentication, object, config, result);
}
return result;
}
public List<AfterInvocationProvider> getProviders() {
return this.providers;
}
public void setProviders(List<?> newList) {
checkIfValidList(newList);
this.providers = new ArrayList<>(newList.size());
for (Object currentObject : newList) {
Assert.isInstanceOf(AfterInvocationProvider.class, currentObject, () -> "AfterInvocationProvider "
+ currentObject.getClass().getName() + " must implement AfterInvocationProvider");
this.providers.add((AfterInvocationProvider) currentObject);
}
}
private void checkIfValidList(List<?> listToCheck) {
Assert.isTrue(!CollectionUtils.isEmpty(listToCheck), "A list of AfterInvocationProviders is required");
}
@Override
public boolean supports(ConfigAttribute attribute) {
for (AfterInvocationProvider provider : this.providers) {
logger.debug(LogMessage.format("Evaluating %s against %s", attribute, provider));
if (provider.supports(attribute)) {
return true;
}
}
return false;
}
/**
* Iterates through all <code>AfterInvocationProvider</code>s and ensures each can
* support the presented class.
* <p>
* If one or more providers cannot support the presented class, <code>false</code> is
* returned.
* @param clazz the secure object class being queries
* @return if the <code>AfterInvocationProviderManager</code> can support the secure
* object class, which requires every one of its <code>AfterInvocationProvider</code>s
* to support the secure object class
*/
@Override
public boolean supports(Class<?> clazz) {
for (AfterInvocationProvider provider : this.providers) {
if (!provider.supports(clazz)) {
return false;
}
}
return true;
}
}
@@ -1,72 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept;
import java.util.Collection;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.context.SecurityContext;
/**
* A return object received by {@link AbstractSecurityInterceptor} subclasses.
* <p>
* This class reflects the status of the security interception, so that the final call to
* {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor#afterInvocation(InterceptorStatusToken, Object)}
* can tidy up correctly.
*
* @author Ben Alex
* @see org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor
* @see org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor
* @deprecated Use delegation with {@link AuthorizationManager}
*/
@Deprecated
public class InterceptorStatusToken {
private SecurityContext securityContext;
private Collection<ConfigAttribute> attr;
private Object secureObject;
private boolean contextHolderRefreshRequired;
public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
Collection<ConfigAttribute> attributes, Object secureObject) {
this.securityContext = securityContext;
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
this.attr = attributes;
this.secureObject = secureObject;
}
public Collection<ConfigAttribute> getAttributes() {
return this.attr;
}
public SecurityContext getSecurityContext() {
return this.securityContext;
}
public Object getSecureObject() {
return this.secureObject;
}
public boolean isContextHolderRefreshRequired() {
return this.contextHolderRefreshRequired;
}
}
@@ -1,95 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept;
import java.util.Collection;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Allows users to determine whether they have "before invocation" privileges for a given
* method invocation.
* <p>
* Of course, if an
* {@link org.springframework.security.access.intercept.AfterInvocationManager} is used to
* authorize the <em>result</em> of a method invocation, this class cannot assist
* determine whether or not the <code>AfterInvocationManager</code> will enable access.
* Instead this class aims to allow applications to determine whether or not the current
* principal would be allowed to at least attempt to invoke the method, irrespective of
* the "after" invocation handling.
* </p>
*
* @author Ben Alex
* @deprecated Use {@link org.springframework.security.authorization.AuthorizationManager}
* instead
*/
@NullUnmarked
@Deprecated
public class MethodInvocationPrivilegeEvaluator implements InitializingBean {
protected static final Log logger = LogFactory.getLog(MethodInvocationPrivilegeEvaluator.class);
@SuppressWarnings("NullAway.Init")
private @Nullable AbstractSecurityInterceptor securityInterceptor;
@Override
public void afterPropertiesSet() {
Assert.notNull(this.securityInterceptor, "SecurityInterceptor required");
}
public boolean isAllowed(MethodInvocation invocation, Authentication authentication) {
Assert.notNull(invocation, "MethodInvocation required");
Assert.notNull(invocation.getMethod(), "MethodInvocation must provide a non-null getMethod()");
Collection<ConfigAttribute> attrs = this.securityInterceptor.obtainSecurityMetadataSource()
.getAttributes(invocation);
if (attrs == null) {
return !this.securityInterceptor.isRejectPublicInvocations();
}
if (authentication == null || authentication.getAuthorities().isEmpty()) {
return false;
}
try {
this.securityInterceptor.getAccessDecisionManager().decide(authentication, invocation, attrs);
return true;
}
catch (AccessDeniedException unauthorized) {
logger.debug(LogMessage.format("%s denied for %s", invocation, authentication), unauthorized);
return false;
}
}
public void setSecurityInterceptor(AbstractSecurityInterceptor securityInterceptor) {
Assert.notNull(securityInterceptor, "AbstractSecurityInterceptor cannot be null");
Assert.isTrue(MethodInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
"AbstractSecurityInterceptor does not support MethodInvocations");
Assert.notNull(securityInterceptor.getAccessDecisionManager(),
"AbstractSecurityInterceptor must provide a non-null AccessDecisionManager");
this.securityInterceptor = securityInterceptor;
}
}
@@ -1,92 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that can authenticate a
* {@link RunAsUserToken}.
* <P>
* Configured in the bean context with a key that should match the key used by adapters to
* generate the <code>RunAsUserToken</code>. It treats as valid any
* <code>RunAsUserToken</code> instance presenting a hash code that matches the
* <code>RunAsImplAuthenticationProvider</code>-configured key.
* </p>
* <P>
* If the key does not match, a <code>BadCredentialsException</code> is thrown.
* </p>
*
* @deprecated Authentication is now separated from authorization in Spring Security. This
* class is only used by now-deprecated components. There is not yet an equivalent
* replacement in Spring Security.
*/
@NullUnmarked
@Deprecated
public class RunAsImplAuthenticationProvider implements InitializingBean, AuthenticationProvider, MessageSourceAware {
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
@SuppressWarnings("NullAway.Init")
private @Nullable String key;
@Override
public void afterPropertiesSet() {
Assert.notNull(this.key, "A Key is required and should match that configured for the RunAsManagerImpl");
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
RunAsUserToken token = (RunAsUserToken) authentication;
if (token.getKeyHash() != this.key.hashCode()) {
throw new BadCredentialsException(this.messages.getMessage("RunAsImplAuthenticationProvider.incorrectKey",
"The presented RunAsUserToken does not contain the expected key"));
}
return authentication;
}
public String getKey() {
return this.key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
@Override
public boolean supports(Class<?> authentication) {
return RunAsUserToken.class.isAssignableFrom(authentication);
}
}
@@ -1,140 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept.aopalliance;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Advisor driven by a {@link MethodSecurityMetadataSource}, used to exclude a
* {@link MethodInterceptor} from public (non-secure) methods.
* <p>
* Because the AOP framework caches advice calculations, this is normally faster than just
* letting the <code>MethodInterceptor</code> run and find out itself that it has no work
* to do.
* <p>
* This class also allows the use of Spring's {@code DefaultAdvisorAutoProxyCreator},
* which makes configuration easier than setup a <code>ProxyFactoryBean</code> for each
* object requiring security. Note that autoproxying is not supported for BeanFactory
* implementations, as post-processing is automatic only for application contexts.
* <p>
* Based on Spring's TransactionAttributeSourceAdvisor.
*
* @author Ben Alex
* @author Luke Taylor
* @deprecated Use
* <code>org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity</code>
* or publish interceptors directly
*/
@NullUnmarked
@Deprecated
@SuppressWarnings("serial")
public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
private transient MethodSecurityMetadataSource attributeSource;
private transient @Nullable MethodInterceptor interceptor;
private final Pointcut pointcut = new MethodSecurityMetadataSourcePointcut();
private @Nullable BeanFactory beanFactory;
private final String adviceBeanName;
private final String metadataSourceBeanName;
private transient volatile Object adviceMonitor = new Object();
/**
* Alternative constructor for situations where we want the advisor decoupled from the
* advice. Instead the advice bean name should be set. This prevents eager
* instantiation of the interceptor (and hence the AuthenticationManager). See
* SEC-773, for example. The metadataSourceBeanName is used rather than a direct
* reference to support serialization via a bean factory lookup.
* @param adviceBeanName name of the MethodSecurityInterceptor bean
* @param attributeSource the SecurityMetadataSource (should be the same as the one
* used on the interceptor)
* @param attributeSourceBeanName the bean name of the attributeSource (required for
* serialization)
*/
public MethodSecurityMetadataSourceAdvisor(String adviceBeanName, MethodSecurityMetadataSource attributeSource,
String attributeSourceBeanName) {
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
Assert.notNull(attributeSource, "The attributeSource cannot be null");
Assert.notNull(attributeSourceBeanName, "The attributeSourceBeanName cannot be null");
this.adviceBeanName = adviceBeanName;
this.attributeSource = attributeSource;
this.metadataSourceBeanName = attributeSourceBeanName;
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
synchronized (this.adviceMonitor) {
if (this.interceptor == null) {
Assert.notNull(this.adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
this.interceptor = this.beanFactory.getBean(this.adviceBeanName, MethodInterceptor.class);
}
return this.interceptor;
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
this.adviceMonitor = new Object();
this.attributeSource = this.beanFactory.getBean(this.metadataSourceBeanName,
MethodSecurityMetadataSource.class);
}
class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method m, Class<?> targetClass) {
MethodSecurityMetadataSource source = MethodSecurityMetadataSourceAdvisor.this.attributeSource;
return !CollectionUtils.isEmpty(source.getAttributes(m, targetClass));
}
}
}
@@ -1,24 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Enforces security for AOP Alliance <code>MethodInvocation</code>s, such as via Spring
* AOP.
*/
@NullMarked
package org.springframework.security.access.intercept.aopalliance;
import org.jspecify.annotations.NullMarked;
@@ -1,107 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.intercept.aspectj;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.util.Assert;
/**
* Decorates a JoinPoint to allow it to be used with method-security infrastructure
* classes which support {@code MethodInvocation} instances.
*
* @author Luke Taylor
* @since 3.0.3
* @deprecated This class will be removed from the public API. See
* `JoinPointMethodInvocation` in `spring-security-aspects` for its replacement
*/
@NullUnmarked
@Deprecated
public final class MethodInvocationAdapter implements MethodInvocation {
private final ProceedingJoinPoint jp;
private final Method method;
private final Object target;
MethodInvocationAdapter(JoinPoint jp) {
this.jp = (ProceedingJoinPoint) jp;
if (jp.getTarget() != null) {
this.target = jp.getTarget();
}
else {
// SEC-1295: target may be null if an ITD is in use
this.target = jp.getSignature().getDeclaringType();
}
String targetMethodName = jp.getStaticPart().getSignature().getName();
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
Class<?> declaringType = jp.getStaticPart().getSignature().getDeclaringType();
this.method = findMethod(targetMethodName, declaringType, types);
Assert.notNull(this.method, () -> "Could not obtain target method from JoinPoint: '" + jp + "'");
}
private Method findMethod(String name, Class<?> declaringType, Class<?>[] params) {
Method method = null;
try {
method = declaringType.getMethod(name, params);
}
catch (NoSuchMethodException ignored) {
}
if (method == null) {
try {
method = declaringType.getDeclaredMethod(name, params);
}
catch (NoSuchMethodException ignored) {
}
}
return method;
}
@Override
public Method getMethod() {
return this.method;
}
@Override
public Object[] getArguments() {
return this.jp.getArgs();
}
@Override
public AccessibleObject getStaticPart() {
return this.method;
}
@Override
public Object getThis() {
return this.target;
}
@Override
public Object proceed() throws Throwable {
return this.jp.proceed();
}
}
@@ -1,24 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Enforces security for AspectJ <code>JointPoint</code>s, delegating secure object
* callbacks to the calling aspect.
*/
@NullMarked
package org.springframework.security.access.intercept.aspectj;
import org.jspecify.annotations.NullMarked;
@@ -1,39 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Abstract level security interception classes which are responsible for enforcing the
* configured security constraints for a secure object.
* <p>
* A <i>secure object</i> is a term frequently used throughout the security system. It
* does <b>not</b> refer to a business object that is being secured, but instead refers to
* some infrastructure object that can have security facilities provided for it by Spring
* Security. For example, one secure object would be <code>MethodInvocation</code>, whilst
* another would be HTTP {@code org.springframework.security.web.FilterInvocation}. Note
* these are infrastructure objects and their design allows them to represent a large
* variety of actual resources that might need to be secured, such as business objects or
* HTTP request URLs.
* <p>
* Each secure object typically has its own interceptor package. Each package usually
* includes a concrete security interceptor (which subclasses
* {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor}) and
* an appropriate {@link org.springframework.security.access.SecurityMetadataSource} for
* the type of resources the secure object represents.
*/
@NullMarked
package org.springframework.security.access.intercept;
import org.jspecify.annotations.NullMarked;
@@ -1,138 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.method;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Automatically tries a series of method definition sources, relying on the first source
* of metadata that provides a non-null/non-empty response. Provides automatic caching of
* the retrieved metadata.
*
* @author Ben Alex
* @author Luke Taylor
* @deprecated Use the {@code use-authorization-manager} attribute for
* {@code <method-security>} and {@code <intercept-methods>} instead or use
* annotation-based or {@link AuthorizationManager}-based authorization
*/
@Deprecated
public final class DelegatingMethodSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
private static final List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections.emptyList();
private final List<MethodSecurityMetadataSource> methodSecurityMetadataSources;
private final Map<DefaultCacheKey, Collection<ConfigAttribute>> attributeCache = new HashMap<>();
public DelegatingMethodSecurityMetadataSource(List<MethodSecurityMetadataSource> methodSecurityMetadataSources) {
Assert.notNull(methodSecurityMetadataSources, "MethodSecurityMetadataSources cannot be null");
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
}
@Override
public Collection<ConfigAttribute> getAttributes(Method method, @Nullable Class<?> targetClass) {
DefaultCacheKey cacheKey = new DefaultCacheKey(method, targetClass);
synchronized (this.attributeCache) {
Collection<ConfigAttribute> cached = this.attributeCache.get(cacheKey);
// Check for canonical value indicating there is no config attribute,
if (cached != null) {
return cached;
}
// No cached value, so query the sources to find a result
Collection<ConfigAttribute> attributes = null;
for (MethodSecurityMetadataSource s : this.methodSecurityMetadataSources) {
attributes = s.getAttributes(method, targetClass);
if (attributes != null && !attributes.isEmpty()) {
break;
}
}
// Put it in the cache.
if (attributes == null || attributes.isEmpty()) {
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
return NULL_CONFIG_ATTRIBUTE;
}
this.logger.debug(LogMessage.format("Caching method [%s] with attributes %s", cacheKey, attributes));
this.attributeCache.put(cacheKey, attributes);
return attributes;
}
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
Set<ConfigAttribute> set = new HashSet<>();
for (MethodSecurityMetadataSource s : this.methodSecurityMetadataSources) {
Collection<ConfigAttribute> attrs = s.getAllConfigAttributes();
if (attrs != null) {
set.addAll(attrs);
}
}
return set;
}
public List<MethodSecurityMetadataSource> getMethodSecurityMetadataSources() {
return this.methodSecurityMetadataSources;
}
private static class DefaultCacheKey {
private final Method method;
private final @Nullable Class<?> targetClass;
DefaultCacheKey(Method method, @Nullable Class<?> targetClass) {
this.method = method;
this.targetClass = targetClass;
}
@Override
public boolean equals(@Nullable Object other) {
if (!(other instanceof DefaultCacheKey otherKey)) {
return false;
}
return (this.method.equals(otherKey.method)
&& ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
}
@Override
public int hashCode() {
return this.method.hashCode() * 21 + ((this.targetClass != null) ? this.targetClass.hashCode() : 0);
}
@Override
public String toString() {
String targetClassName = (this.targetClass != null) ? this.targetClass.getName() : "-";
return "CacheKey[" + targetClassName + "; " + this.method + "]";
}
}
}
@@ -1,290 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.method;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Stores a list of <tt>ConfigAttribute</tt>s for a method or class signature.
*
* <p>
* This class is the preferred implementation of {@link MethodSecurityMetadataSource} for
* XML-based definition of method security metadata. To assist in XML-based definition,
* wildcard support is provided.
* </p>
*
* @author Ben Alex
* @since 2.0
* @deprecated Use the {@code use-authorization-manager} attribute for
* {@code <method-security>} and {@code <intercept-methods>} instead or use
* annotation-based or {@link AuthorizationManager}-based authorization
*/
@NullUnmarked
@Deprecated
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
implements BeanClassLoaderAware {
@SuppressWarnings("NullAway")
private @Nullable ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/**
* Map from RegisteredMethod to ConfigAttribute list
*/
protected final Map<RegisteredMethod, List<ConfigAttribute>> methodMap = new HashMap<>();
/**
* Map from RegisteredMethod to name pattern used for registration
*/
private final Map<RegisteredMethod, String> nameMap = new HashMap<>();
public MapBasedMethodSecurityMetadataSource() {
}
/**
* Creates the <tt>MapBasedMethodSecurityMetadataSource</tt> from a
* @param methodMap map of method names to <tt>ConfigAttribute</tt>s.
*/
public MapBasedMethodSecurityMetadataSource(Map<String, List<ConfigAttribute>> methodMap) {
for (Map.Entry<String, List<ConfigAttribute>> entry : methodMap.entrySet()) {
addSecureMethod(entry.getKey(), entry.getValue());
}
}
/**
* Implementation does not support class-level attributes.
*/
@Override
protected @Nullable Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
return null;
}
/**
* Will walk the method inheritance tree to find the most specific declaration
* applicable.
*/
@Override
protected @Nullable Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
if (targetClass == null) {
return null;
}
return findAttributesSpecifiedAgainst(method, targetClass);
}
private @Nullable List<ConfigAttribute> findAttributesSpecifiedAgainst(Method method, Class<?> clazz) {
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
if (this.methodMap.containsKey(registeredMethod)) {
return this.methodMap.get(registeredMethod);
}
// Search superclass
if (clazz.getSuperclass() != null) {
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
}
return null;
}
/**
* Add configuration attributes for a secure method. Method names can end or start
* with <code>*</code> for matching multiple methods.
* @param name type and method name, separated by a dot
* @param attr the security attributes associated with the method
*/
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
int lastDotIndex = name.lastIndexOf(".");
Assert.isTrue(lastDotIndex != -1, () -> "'" + name + "' is not a valid method name: format is FQN.methodName");
String methodName = name.substring(lastDotIndex + 1);
Assert.hasText(methodName, () -> "Method not found for '" + name + "'");
String typeName = name.substring(0, lastDotIndex);
Class<?> type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
addSecureMethod(type, methodName, attr);
}
/**
* Add configuration attributes for a secure method. Mapped method names can end or
* start with <code>*</code> for matching multiple methods.
* @param javaType target interface or class the security configuration attribute
* applies to
* @param mappedName mapped method name, which the javaType has declared or inherited
* @param attr required authorities associated with the method
*/
public void addSecureMethod(Class<?> javaType, String mappedName, List<ConfigAttribute> attr) {
String name = javaType.getName() + '.' + mappedName;
this.logger.debug(LogMessage.format("Request to add secure method [%s] with attributes [%s]", name, attr));
Method[] methods = javaType.getMethods();
List<Method> matchingMethods = new ArrayList<>();
for (Method method : methods) {
if (method.getName().equals(mappedName) || isMatch(method.getName(), mappedName)) {
matchingMethods.add(method);
}
}
Assert.notEmpty(matchingMethods, () -> "Couldn't find method '" + mappedName + "' on '" + javaType + "'");
registerAllMatchingMethods(javaType, attr, name, matchingMethods);
}
private void registerAllMatchingMethods(Class<?> javaType, List<ConfigAttribute> attr, String name,
List<Method> matchingMethods) {
for (Method method : matchingMethods) {
RegisteredMethod registeredMethod = new RegisteredMethod(method, javaType);
String regMethodName = this.nameMap.get(registeredMethod);
if ((regMethodName == null) || (!regMethodName.equals(name) && (regMethodName.length() <= name.length()))) {
// no already registered method name, or more specific
// method name specification (now) -> (re-)register method
if (regMethodName != null) {
this.logger.debug(LogMessage.format(
"Replacing attributes for secure method [%s]: current name [%s] is more specific than [%s]",
method, name, regMethodName));
}
this.nameMap.put(registeredMethod, name);
addSecureMethod(registeredMethod, attr);
}
else {
this.logger.debug(LogMessage.format(
"Keeping attributes for secure method [%s]: current name [%s] is not more specific than [%s]",
method, name, regMethodName));
}
}
}
/**
* Adds configuration attributes for a specific method, for example where the method
* has been matched using a pointcut expression. If a match already exists in the map
* for the method, then the existing match will be retained, so that if this method is
* called for a more general pointcut it will not override a more specific one which
* has already been added.
* <p>
* This method should only be called during initialization of the {@code BeanFactory}.
*/
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
RegisteredMethod key = new RegisteredMethod(method, javaType);
if (this.methodMap.containsKey(key)) {
this.logger.debug(LogMessage.format("Method [%s] is already registered with attributes [%s]", method,
this.methodMap.get(key)));
return;
}
this.methodMap.put(key, attr);
}
/**
* Add configuration attributes for a secure method.
* @param method the method to be secured
* @param attr required authorities associated with the method
*/
private void addSecureMethod(RegisteredMethod method, List<ConfigAttribute> attr) {
Assert.notNull(method, "RegisteredMethod required");
Assert.notNull(attr, "Configuration attribute required");
this.logger.info(LogMessage.format("Adding secure method [%s] with attributes [%s]", method, attr));
this.methodMap.put(method, attr);
}
/**
* Obtains the configuration attributes explicitly defined against this bean.
* @return the attributes explicitly defined against this bean
*/
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
Set<ConfigAttribute> allAttributes = new HashSet<>();
this.methodMap.values().forEach(allAttributes::addAll);
return allAttributes;
}
/**
* Return if the given method name matches the mapped name. The default implementation
* checks for "xxx" and "xxx" matches.
* @param methodName the method name of the class
* @param mappedName the name in the descriptor
* @return if the names match
*/
private boolean isMatch(String methodName, String mappedName) {
return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1)))
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
}
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
Assert.notNull(beanClassLoader, "Bean class loader required");
this.beanClassLoader = beanClassLoader;
}
/**
* @return map size (for unit tests and diagnostics)
*/
public int getMethodMapSize() {
return this.methodMap.size();
}
/**
* Stores both the Java Method as well as the Class we obtained the Method from. This
* is necessary because Method only provides us access to the declaring class. It
* doesn't provide a way for us to introspect which Class the Method was registered
* against. If a given Class inherits and redeclares a method (i.e. calls super();)
* the registered Class and declaring Class are the same. If a given class merely
* inherits but does not redeclare a method, the registered Class will be the Class
* we're invoking against and the Method will provide details of the declared class.
*/
private static class RegisteredMethod {
private final Method method;
private final Class<?> registeredJavaType;
RegisteredMethod(Method method, Class<?> registeredJavaType) {
Assert.notNull(method, "Method required");
Assert.notNull(registeredJavaType, "Registered Java Type required");
this.method = method;
this.registeredJavaType = registeredJavaType;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RegisteredMethod rhs) {
return this.method.equals(rhs.method) && this.registeredJavaType.equals(rhs.registeredJavaType);
}
return false;
}
@Override
public int hashCode() {
return this.method.hashCode() * this.registeredJavaType.hashCode();
}
@Override
public String toString() {
return "RegisteredMethod[" + this.registeredJavaType.getName() + "; " + this.method + "]";
}
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.method;
import java.lang.reflect.Method;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.authorization.AuthorizationManager;
/**
* Interface for <code>SecurityMetadataSource</code> implementations that are designed to
* perform lookups keyed on <code>Method</code>s.
*
* @author Ben Alex
* @see org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager
* @see org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager
* @deprecated Use the {@code use-authorization-manager} attribute for
* {@code <method-security>} and {@code <intercept-methods>} instead or use
* annotation-based or {@link AuthorizationManager}-based authorization
*/
@Deprecated
public interface MethodSecurityMetadataSource extends SecurityMetadataSource {
Collection<ConfigAttribute> getAttributes(Method method, @Nullable Class<?> targetClass);
}
@@ -1,49 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.method;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.security.core.parameters.AnnotationParameterNameDiscoverer;
/**
* An annotation that can be used along with {@link AnnotationParameterNameDiscoverer} to
* specify parameter names. This is useful for interfaces prior to JDK 8 which cannot
* contain the parameter names.
*
* @see AnnotationParameterNameDiscoverer
* @author Rob Winch
* @since 3.2
* @deprecated use @{code org.springframework.security.core.parameters.P}
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Deprecated
public @interface P {
/**
* The parameter name
* @return
*/
String value();
}
@@ -1,24 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Provides {@code SecurityMetadataSource} implementations for securing Java method
* invocations via different AOP libraries.
*/
@NullMarked
package org.springframework.security.access.method;
import org.jspecify.annotations.NullMarked;
@@ -1,87 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.prepost;
import java.util.Collection;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AfterInvocationProvider;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
/**
* <tt>AfterInvocationProvider</tt> which delegates to a
* {@link PostInvocationAuthorizationAdvice} instance passing it the
* <tt>PostInvocationAttribute</tt> created from @PostAuthorize and @PostFilter
* annotations.
*
* @author Luke Taylor
* @author Alexander Furer
* @since 3.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor}
* instead
*/
@NullUnmarked
@Deprecated
public class PostInvocationAdviceProvider implements AfterInvocationProvider {
protected final Log logger = LogFactory.getLog(getClass());
private final PostInvocationAuthorizationAdvice postAdvice;
public PostInvocationAdviceProvider(PostInvocationAuthorizationAdvice postAdvice) {
this.postAdvice = postAdvice;
}
@Override
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
PostInvocationAttribute postInvocationAttribute = findPostInvocationAttribute(config);
if (postInvocationAttribute == null) {
return returnedObject;
}
return this.postAdvice.after(authentication, (MethodInvocation) object, postInvocationAttribute,
returnedObject);
}
private @Nullable PostInvocationAttribute findPostInvocationAttribute(Collection<ConfigAttribute> config) {
for (ConfigAttribute attribute : config) {
if (attribute instanceof PostInvocationAttribute) {
return (PostInvocationAttribute) attribute;
}
}
return null;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof PostInvocationAttribute;
}
@Override
public boolean supports(Class<?> clazz) {
return MethodInvocation.class.isAssignableFrom(clazz);
}
}
@@ -1,196 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.prepost;
import java.lang.reflect.Method;
import java.util.Collection;
import kotlinx.coroutines.reactive.ReactiveFlowKt;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.util.Assert;
/**
* A {@link MethodInterceptor} that supports {@link PreAuthorize} and
* {@link PostAuthorize} for methods that return {@link Mono} or {@link Flux} and Kotlin
* coroutine functions.
*
* @author Rob Winch
* @author Eleftheria Stein
* @since 5.0
* @deprecated Use
* {@link org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor}
* or
* {@link org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor}
*/
@NullUnmarked
@Deprecated
public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor {
private Authentication anonymous = new AnonymousAuthenticationToken("key", "anonymous",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
private final MethodSecurityMetadataSource attributeSource;
private final PreInvocationAuthorizationAdvice preInvocationAdvice;
private final PostInvocationAuthorizationAdvice postAdvice;
private static final String COROUTINES_FLOW_CLASS_NAME = "kotlinx.coroutines.flow.Flow";
private static final int RETURN_TYPE_METHOD_PARAMETER_INDEX = -1;
/**
* Creates a new instance
* @param attributeSource the {@link MethodSecurityMetadataSource} to use
* @param preInvocationAdvice the {@link PreInvocationAuthorizationAdvice} to use
* @param postInvocationAdvice the {@link PostInvocationAuthorizationAdvice} to use
*/
public PrePostAdviceReactiveMethodInterceptor(MethodSecurityMetadataSource attributeSource,
PreInvocationAuthorizationAdvice preInvocationAdvice,
PostInvocationAuthorizationAdvice postInvocationAdvice) {
Assert.notNull(attributeSource, "attributeSource cannot be null");
Assert.notNull(preInvocationAdvice, "preInvocationAdvice cannot be null");
Assert.notNull(postInvocationAdvice, "postInvocationAdvice cannot be null");
this.attributeSource = attributeSource;
this.preInvocationAdvice = preInvocationAdvice;
this.postAdvice = postInvocationAdvice;
}
@Override
public Object invoke(final MethodInvocation invocation) {
Method method = invocation.getMethod();
Class<?> returnType = method.getReturnType();
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasFlowReturnType = COROUTINES_FLOW_CLASS_NAME
.equals(new MethodParameter(method, RETURN_TYPE_METHOD_PARAMETER_INDEX).getParameterType().getName());
boolean hasReactiveReturnType = Publisher.class.isAssignableFrom(returnType) || isSuspendingFunction
|| hasFlowReturnType;
Assert.state(hasReactiveReturnType,
() -> "The returnType " + returnType + " on " + method
+ " must return an instance of org.reactivestreams.Publisher "
+ "(i.e. Mono / Flux) or the function must be a Kotlin coroutine "
+ "function in order to support Reactor Context");
Class<?> targetClass = invocation.getThis().getClass();
Collection<ConfigAttribute> attributes = this.attributeSource.getAttributes(method, targetClass);
PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
// @formatter:off
Mono<Authentication> toInvoke = ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.defaultIfEmpty(this.anonymous)
.filter((auth) -> this.preInvocationAdvice.before(auth, invocation, preAttr))
.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Denied"))));
// @formatter:on
PostInvocationAttribute attr = findPostInvocationAttribute(attributes);
if (Mono.class.isAssignableFrom(returnType)) {
return toInvoke.flatMap((auth) -> PrePostAdviceReactiveMethodInterceptor.<Mono<?>>proceed(invocation)
.map((r) -> (attr != null) ? this.postAdvice.after(auth, invocation, attr, r) : r));
}
if (Flux.class.isAssignableFrom(returnType)) {
return toInvoke.flatMapMany((auth) -> PrePostAdviceReactiveMethodInterceptor.<Flux<?>>proceed(invocation)
.map((r) -> (attr != null) ? this.postAdvice.after(auth, invocation, attr, r) : r));
}
if (hasFlowReturnType) {
if (isSuspendingFunction) {
return toInvoke
.flatMapMany((auth) -> Flux.from(PrePostAdviceReactiveMethodInterceptor.proceed(invocation))
.map((r) -> (attr != null) ? this.postAdvice.after(auth, invocation, attr, r) : r));
}
else {
ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(returnType);
Assert.state(adapter != null, () -> "The returnType " + returnType + " on " + method
+ " must have a org.springframework.core.ReactiveAdapter registered");
Flux<?> response = toInvoke.flatMapMany((auth) -> Flux
.from(adapter.toPublisher(PrePostAdviceReactiveMethodInterceptor.flowProceed(invocation)))
.map((r) -> (attr != null) ? this.postAdvice.after(auth, invocation, attr, r) : r));
return KotlinDelegate.asFlow(response);
}
}
return toInvoke.flatMap((auth) -> Mono.from(PrePostAdviceReactiveMethodInterceptor.proceed(invocation))
.map((r) -> (attr != null) ? this.postAdvice.after(auth, invocation, attr, r) : r));
}
@SuppressWarnings("unchecked")
private static <T extends Publisher<?>> @Nullable T proceed(final MethodInvocation invocation) {
try {
return (T) invocation.proceed();
}
catch (Throwable throwable) {
throw Exceptions.propagate(throwable);
}
}
private static @Nullable Object flowProceed(final MethodInvocation invocation) {
try {
return invocation.proceed();
}
catch (Throwable throwable) {
throw Exceptions.propagate(throwable);
}
}
private static @Nullable PostInvocationAttribute findPostInvocationAttribute(Collection<ConfigAttribute> config) {
for (ConfigAttribute attribute : config) {
if (attribute instanceof PostInvocationAttribute) {
return (PostInvocationAttribute) attribute;
}
}
return null;
}
private static @Nullable PreInvocationAttribute findPreInvocationAttribute(Collection<ConfigAttribute> config) {
for (ConfigAttribute attribute : config) {
if (attribute instanceof PreInvocationAttribute) {
return (PreInvocationAttribute) attribute;
}
}
return null;
}
/**
* Inner class to avoid a hard dependency on Kotlin at runtime.
*/
private static class KotlinDelegate {
private static Object asFlow(Publisher<?> publisher) {
return ReactiveFlowKt.asFlow(publisher);
}
}
}
@@ -1,145 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.prepost;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource;
import org.springframework.util.ClassUtils;
/**
* <tt>MethodSecurityMetadataSource</tt> which extracts metadata from the @PreFilter
* and @PreAuthorize annotations placed on a method. This class is merely responsible for
* locating the relevant annotations (if any). It delegates the actual
* <tt>ConfigAttribute</tt> creation to its {@link PrePostInvocationAttributeFactory},
* thus decoupling itself from the mechanism which will enforce the annotations'
* behaviour.
* <p>
* Annotations may be specified on classes or methods, and method-specific annotations
* will take precedence. If you use any annotation and do not specify a pre-authorization
* condition, then the method will be allowed as if a @PreAuthorize("permitAll") were
* present.
* <p>
* Since we are handling multiple annotations here, it's possible that we may have to
* combine annotations defined in multiple locations for a single method - they may be
* defined on the method itself, or at interface or class level.
*
* @author Luke Taylor
* @since 3.0
* @see PreInvocationAuthorizationAdviceVoter
* @deprecated Use
* {@link org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager}
* and
* {@link org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager}
* instead
*/
@NullUnmarked
@Deprecated
public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
private final PrePostInvocationAttributeFactory attributeFactory;
public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
this.attributeFactory = attributeFactory;
}
@Override
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return Collections.emptyList();
}
PreFilter preFilter = findAnnotation(method, targetClass, PreFilter.class);
PreAuthorize preAuthorize = findAnnotation(method, targetClass, PreAuthorize.class);
PostFilter postFilter = findAnnotation(method, targetClass, PostFilter.class);
// TODO: Can we check for void methods and throw an exception here?
PostAuthorize postAuthorize = findAnnotation(method, targetClass, PostAuthorize.class);
if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) {
// There is no meta-data so return
return Collections.emptyList();
}
String preFilterAttribute = (preFilter != null) ? preFilter.value() : null;
String filterObject = (preFilter != null) ? preFilter.filterTarget() : null;
String preAuthorizeAttribute = (preAuthorize != null) ? preAuthorize.value() : null;
String postFilterAttribute = (postFilter != null) ? postFilter.value() : null;
String postAuthorizeAttribute = (postAuthorize != null) ? postAuthorize.value() : null;
ArrayList<ConfigAttribute> attrs = new ArrayList<>(2);
PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute,
filterObject, preAuthorizeAttribute);
if (pre != null) {
attrs.add(pre);
}
PostInvocationAttribute post = this.attributeFactory.createPostInvocationAttribute(postFilterAttribute,
postAuthorizeAttribute);
if (post != null) {
attrs.add(post);
}
attrs.trimToSize();
return attrs;
}
@Override
public @Nullable Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
/**
* See
* {@link org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource#getAttributes(Method, Class)}
* for the logic of this method. The ordering here is slightly different in that we
* consider method-specific annotations on an interface before class-level ones.
*/
private <A extends Annotation> @Nullable A findAnnotation(Method method, Class<?> targetClass,
Class<A> annotationClass) {
// The method may be on an interface, but we need attributes from the target
// class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
A annotation = AnnotationUtils.findAnnotation(specificMethod, annotationClass);
if (annotation != null) {
this.logger.debug(LogMessage.format("%s found on specific method: %s", annotation, specificMethod));
return annotation;
}
// Check the original (e.g. interface) method
if (specificMethod != method) {
annotation = AnnotationUtils.findAnnotation(method, annotationClass);
if (annotation != null) {
this.logger.debug(LogMessage.format("%s found on: %s", annotation, method));
return annotation;
}
}
// Check the class-level (note declaringClass, not targetClass, which may not
// actually implement the method)
annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
if (annotation != null) {
this.logger
.debug(LogMessage.format("%s found on: %s", annotation, specificMethod.getDeclaringClass().getName()));
return annotation;
}
return null;
}
}
@@ -1,40 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.prepost;
import org.jspecify.annotations.Nullable;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.security.authorization.AuthorizationManager;
/**
* @author Luke Taylor
* @since 3.0
* @see org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor
* @see org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor
* @deprecated Use delegation with {@link AuthorizationManager}
*/
@Deprecated
public interface PrePostInvocationAttributeFactory extends AopInfrastructureBean {
PreInvocationAttribute createPreInvocationAttribute(@Nullable String preFilterAttribute,
@Nullable String filterObject, @Nullable String preAuthorizeAttribute);
PostInvocationAttribute createPostInvocationAttribute(@Nullable String postFilterAttribute,
@Nullable String postAuthorizeAttribute);
}
@@ -1,75 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.vote;
import org.aopalliance.intercept.MethodInvocation;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.util.Assert;
/**
* Provides helper methods for writing domain object ACL voters. Not bound to any
* particular ACL system.
*
* @author Ben Alex
* @deprecated Now used by only-deprecated classes. Generally speaking, in-memory ACL is
* no longer advised, so no replacement is planned at this point.
*/
@NullUnmarked
@Deprecated
public abstract class AbstractAclVoter implements AccessDecisionVoter<MethodInvocation> {
@SuppressWarnings("NullAway.Init")
private @Nullable Class<?> processDomainObjectClass;
protected Object getDomainObjectInstance(MethodInvocation invocation) {
Object[] args = invocation.getArguments();
Class<?>[] params = invocation.getMethod().getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (this.processDomainObjectClass.isAssignableFrom(params[i])) {
return args[i];
}
}
throw new AuthorizationServiceException("MethodInvocation: " + invocation
+ " did not provide any argument of type: " + this.processDomainObjectClass);
}
public Class<?> getProcessDomainObjectClass() {
return this.processDomainObjectClass;
}
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
this.processDomainObjectClass = processDomainObjectClass;
}
/**
* This implementation supports only <code>MethodSecurityInterceptor</code>, because
* it queries the presented <code>MethodInvocation</code>.
* @param clazz the secure object
* @return <code>true</code> if the secure object is <code>MethodInvocation</code>,
* <code>false</code> otherwise
*/
@Override
public boolean supports(Class<?> clazz) {
return (MethodInvocation.class.isAssignableFrom(clazz));
}
}
@@ -1,119 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.vote;
import java.util.Collection;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Votes if a {@link ConfigAttribute#getAttribute()} of
* <code>IS_AUTHENTICATED_FULLY</code> or <code>IS_AUTHENTICATED_REMEMBERED</code> or
* <code>IS_AUTHENTICATED_ANONYMOUSLY</code> is present. This list is in order of most
* strict checking to least strict checking.
* <p>
* The current <code>Authentication</code> will be inspected to determine if the principal
* has a particular level of authentication. The "FULLY" authenticated option means the
* user is authenticated fully (i.e.
* {@link org.springframework.security.authentication.AuthenticationTrustResolver#isAnonymous(Authentication)}
* is false and
* {@link org.springframework.security.authentication.AuthenticationTrustResolver#isRememberMe(Authentication)}
* is false). The "REMEMBERED" will grant access if the principal was either authenticated
* via remember-me OR is fully authenticated. The "ANONYMOUSLY" will grant access if the
* principal was authenticated via remember-me, OR anonymously, OR via full
* authentication.
* <p>
* All comparisons and prefixes are case sensitive.
*
* @author Ben Alex
* @deprecated Use
* {@link org.springframework.security.authorization.AuthorityAuthorizationManager}
* instead
*/
@Deprecated
public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
public static final String IS_AUTHENTICATED_FULLY = "IS_AUTHENTICATED_FULLY";
public static final String IS_AUTHENTICATED_REMEMBERED = "IS_AUTHENTICATED_REMEMBERED";
public static final String IS_AUTHENTICATED_ANONYMOUSLY = "IS_AUTHENTICATED_ANONYMOUSLY";
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
private boolean isFullyAuthenticated(Authentication authentication) {
return this.authenticationTrustResolver.isFullyAuthenticated(authentication);
}
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
Assert.notNull(authenticationTrustResolver, "AuthenticationTrustResolver cannot be set to null");
this.authenticationTrustResolver = authenticationTrustResolver;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return (attribute.getAttribute() != null) && (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())
|| IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())
|| IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute()));
}
/**
* This implementation supports any type of class, because it does not query the
* presented secure object.
* @param clazz the secure object type
* @return always {@code true}
*/
@Override
public boolean supports(Class<?> clazz) {
return true;
}
@Override
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
int result = ACCESS_ABSTAIN;
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
if (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())) {
if (isFullyAuthenticated(authentication)) {
return ACCESS_GRANTED;
}
}
if (IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())) {
if (this.authenticationTrustResolver.isRememberMe(authentication)
|| isFullyAuthenticated(authentication)) {
return ACCESS_GRANTED;
}
}
if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) {
if (this.authenticationTrustResolver.isAnonymous(authentication)
|| isFullyAuthenticated(authentication)
|| this.authenticationTrustResolver.isRememberMe(authentication)) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
}
@@ -1,106 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.vote;
import java.util.Collection;
import java.util.List;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
/**
* Simple concrete implementation of
* {@link org.springframework.security.access.AccessDecisionManager} that uses a
* consensus-based approach.
* <p>
* "Consensus" here means majority-rule (ignoring abstains) rather than unanimous
* agreement (ignoring abstains). If you require unanimity, please see
* {@link UnanimousBased}.
*
* @deprecated Use {@link AuthorizationManager} instead
*/
@Deprecated
public class ConsensusBased extends AbstractAccessDecisionManager {
private boolean allowIfEqualGrantedDeniedDecisions = true;
public ConsensusBased(List<AccessDecisionVoter<?>> decisionVoters) {
super(decisionVoters);
}
/**
* This concrete implementation simply polls all configured
* {@link AccessDecisionVoter}s and upon completion determines the consensus of
* granted against denied responses.
* <p>
* If there were an equal number of grant and deny votes, the decision will be based
* on the {@link #isAllowIfEqualGrantedDeniedDecisions()} property (defaults to true).
* <p>
* If every <code>AccessDecisionVoter</code> abstained from voting, the decision will
* be based on the {@link #isAllowIfAllAbstainDecisions()} property (defaults to
* false).
* @param authentication the caller invoking the method
* @param object the secured object
* @param configAttributes the configuration attributes associated with the method
* being invoked
* @throws AccessDeniedException if access is denied
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException {
int grant = 0;
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED -> grant++;
case AccessDecisionVoter.ACCESS_DENIED -> deny++;
default -> {
}
}
}
if (grant > deny) {
return;
}
if (deny > grant) {
throw new AccessDeniedException(
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
if ((grant == deny) && (grant != 0)) {
if (this.allowIfEqualGrantedDeniedDecisions) {
return;
}
throw new AccessDeniedException(
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
public boolean isAllowIfEqualGrantedDeniedDecisions() {
return this.allowIfEqualGrantedDeniedDecisions;
}
public void setAllowIfEqualGrantedDeniedDecisions(boolean allowIfEqualGrantedDeniedDecisions) {
this.allowIfEqualGrantedDeniedDecisions = allowIfEqualGrantedDeniedDecisions;
}
}
@@ -1,59 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access.vote;
import java.util.Collection;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
/**
* Extended RoleVoter which uses a {@link RoleHierarchy} definition to determine the roles
* allocated to the current user before voting.
*
* @author Luke Taylor
* @since 2.0.4
* @deprecated Use
* {@link org.springframework.security.authorization.AuthorityAuthorizationManager#setRoleHierarchy}
* instead
*/
@NullUnmarked
@Deprecated
public class RoleHierarchyVoter extends RoleVoter {
@SuppressWarnings("NullAway")
private @Nullable RoleHierarchy roleHierarchy = null;
public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
this.roleHierarchy = roleHierarchy;
}
/**
* Calls the <tt>RoleHierarchy</tt> to obtain the complete set of user authorities.
*/
@Override
Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
}
}
@@ -1,23 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Implements a vote-based approach to authorization decisions.
*/
@NullMarked
package org.springframework.security.access.vote;
import org.jspecify.annotations.NullMarked;
@@ -1,245 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAclVoter;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* <p>
* Given a domain object instance passed as a method argument, ensures the principal has
* appropriate permission as indicated by the {@link AclService}.
* <p>
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions
* associated with a domain object instance for the current <tt>Authentication</tt>
* object.
* <p>
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the
* {@link #processConfigAttribute}. The provider will then locate the first method
* argument of type {@link #processDomainObjectClass}. Assuming that method argument is
* non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and
* ensure the principal is {@link Acl#isGranted(List, List, boolean)} when presenting the
* {@link #requirePermission} array to that method.
* <p>
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the
* method argument could not be found, an {@link AuthorizationServiceException} will be
* thrown.
* <p>
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each
* will have a different {@link #setProcessDomainObjectClass processDomainObjectClass},
* {@link #processConfigAttribute} and {@link #requirePermission} combination. For
* example, a small application might employ the following instances of
* <tt>AclEntryVoter</tt>:
* <ul>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_READ</code>, require permission
* <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code> (allowing the
* principal to have <b>either</b> of these two permissions)</li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission
* <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code></li>
* </ul>
* Alternatively, you could have used a common superclass or interface for the
* {@link #processDomainObjectClass} if both <code>BankAccount</code> and
* <code>Customer</code> had common parents.
*
* <p>
* If the principal does not have sufficient permissions, the voter will vote to deny
* access.
*
* <p>
* All comparisons and prefixes are case sensitive.
*
* @author Ben Alex
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PreAuthorize("hasPermission(#id, ObjectsReturnType.class, read)")}
*/
@Deprecated
public class AclEntryVoter extends AbstractAclVoter {
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
private final AclService aclService;
private final String processConfigAttribute;
private final List<Permission> requirePermission;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String internalMethod;
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
Assert.isTrue(!ObjectUtils.isEmpty(requirePermission), "One or more requirePermission entries is mandatory");
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = Arrays.asList(requirePermission);
}
/**
* Optionally specifies a method of the domain object that will be used to obtain a
* contained domain object. That contained domain object will be used for the ACL
* evaluation. This is useful if a domain object contains a parent that an ACL
* evaluation should be targeted for, instead of the child domain object (which
* perhaps is being created and as such does not yet have any ACL permissions)
* @return <code>null</code> to use the domain object, or the name of a method (that
* requires no arguments) that should be invoked to obtain an <code>Object</code>
* which will be the domain object used for ACL evaluation
*/
protected String getInternalMethod() {
return this.internalMethod;
}
public void setInternalMethod(String internalMethod) {
this.internalMethod = internalMethod;
}
protected String getProcessConfigAttribute() {
return this.processConfigAttribute;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
}
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attr : attributes) {
if (!supports(attr)) {
continue;
}
// Need to make an access decision on this invocation
// Attempt to locate the domain object instance to process
Object domainObject = getDomainObjectInstance(object);
// If domain object is null, vote to abstain
if (domainObject == null) {
logger.debug("Voting to abstain - domainObject is null");
return ACCESS_ABSTAIN;
}
// Evaluate if we are required to use an inner domain object
if (StringUtils.hasText(this.internalMethod)) {
domainObject = invokeInternalMethod(domainObject);
}
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
Acl acl;
try {
// Lookup only ACLs for SIDs we're interested in
acl = this.aclService.readAclById(objectIdentity, sids);
}
catch (NotFoundException ex) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
return ACCESS_DENIED;
}
try {
if (acl.isGranted(this.requirePermission, sids, false)) {
logger.debug("Voting to grant access");
return ACCESS_GRANTED;
}
logger.debug("Voting to deny access - ACLs returned, but insufficient permissions for this principal");
return ACCESS_DENIED;
}
catch (NotFoundException ex) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
return ACCESS_DENIED;
}
}
// No configuration attribute matched, so abstain
return ACCESS_ABSTAIN;
}
private Object invokeInternalMethod(Object domainObject) {
try {
Class<?> domainObjectType = domainObject.getClass();
Method method = domainObjectType.getMethod(this.internalMethod, new Class[0]);
return method.invoke(domainObject);
}
catch (NoSuchMethodException ex) {
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
+ "' does not provide the requested internalMethod: " + this.internalMethod);
}
catch (IllegalAccessException ex) {
logger.debug("IllegalAccessException", ex);
throw new AuthorizationServiceException(
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
}
catch (InvocationTargetException ex) {
logger.debug("InvocationTargetException", ex);
throw new AuthorizationServiceException(
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
}
}
}
@@ -1,126 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.afterinvocation;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication;
/**
* <p>
* Given a <code>Collection</code> of domain object instances returned from a secure
* object invocation, remove any <code>Collection</code> elements the principal does not
* have appropriate permission to access as defined by the {@link AclService}.
* <p>
* The <code>AclService</code> is used to retrieve the access control list (ACL)
* permissions associated with each <code>Collection</code> domain object instance element
* for the current <code>Authentication</code> object.
* <p>
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()}
* matches the {@link #processConfigAttribute}. The provider will then lookup the ACLs
* from the <code>AclService</code> and ensure the principal is
* {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
* Acl.isGranted()} when presenting the {@link #requirePermission} array to that method.
* <p>
* If the principal does not have permission, that element will not be included in the
* returned <code>Collection</code>.
* <p>
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a
* {@link #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a
* {@link #requirePermission} of <code>BasePermission.READ</code>. These are also the
* defaults.
* <p>
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code>
* <code>Collection</code> will be returned. If the provided <code>returnObject</code> is
* not a <code>Collection</code>, an {@link AuthorizationServiceException} will be thrown.
* <p>
* All comparisons and prefixes are case sensitive.
*
* @author Ben Alex
* @author Paulo Neves
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
* annotations may also prove useful, for example
* {@code @PostFilter("hasPermission(filterObject, read)")}
*/
@Deprecated
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService,
List<Permission> requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
@Override
@SuppressWarnings("unchecked")
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
logger.debug("Return object is null, skipping");
return null;
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
// Need to process the Collection for this invocation
Filterer filterer = getFilterer(returnedObject);
// Locate unauthorised Collection elements
for (Object domainObject : filterer) {
// Ignore nulls or entries which aren't instances of the configured domain
// object class
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
continue;
}
if (!hasPermission(authentication, domainObject)) {
filterer.remove(domainObject);
logger.debug(LogMessage.of(() -> "Principal is NOT authorised for element: " + domainObject));
}
}
return filterer.getFilteredObject();
}
return returnedObject;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Filterer getFilterer(Object returnedObject) {
if (returnedObject instanceof Collection) {
return new CollectionFilterer((Collection) returnedObject);
}
if (returnedObject.getClass().isArray()) {
return new ArrayFilterer((Object[]) returnedObject);
}
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
+ "returnedObject, but the returnedObject was: " + returnedObject);
}
}
@@ -1,105 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.afterinvocation;
import java.lang.reflect.Array;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
/**
* A filter used to filter arrays.
*
* @author Ben Alex
* @author Paulo Neves
* @deprecated please see {@code PostFilter}
*/
@Deprecated
class ArrayFilterer<T> implements Filterer<T> {
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
private final Set<T> removeList;
private final T[] list;
ArrayFilterer(T[] list) {
this.list = list;
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
this.removeList = new HashSet<>();
}
@Override
@SuppressWarnings("unchecked")
public T[] getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = this.list.length;
int sizeOfResultingList = originalSize - this.removeList.size();
T[] filtered = (T[]) Array.newInstance(this.list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < this.list.length; i++) {
T object = this.list[i];
if (!this.removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
logger.debug(LogMessage.of(() -> "Original array contained " + originalSize + " elements; now contains "
+ sizeOfResultingList + " elements"));
return filtered;
}
@Override
public Iterator<T> iterator() {
return new ArrayFiltererIterator();
}
@Override
public void remove(T object) {
this.removeList.add(object);
}
/**
* Iterator for {@link ArrayFilterer} elements.
*/
private class ArrayFiltererIterator implements Iterator<T> {
private int index = 0;
@Override
public boolean hasNext() {
return this.index < ArrayFilterer.this.list.length;
}
@Override
public T next() {
if (hasNext()) {
return ArrayFilterer.this.list[this.index++];
}
throw new NoSuchElementException();
}
}
}
@@ -1,80 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.afterinvocation;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
/**
* A filter used to filter Collections.
*
* @author Ben Alex
* @author Paulo Neves
* @deprecated please see {@code PostFilter}
*/
@Deprecated
class CollectionFilterer<T> implements Filterer<T> {
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
private final Collection<T> collection;
private final Set<T> removeList;
CollectionFilterer(Collection<T> collection) {
this.collection = collection;
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
this.removeList = new HashSet<>();
}
@Override
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator<T> removeIter = this.removeList.iterator();
int originalSize = this.collection.size();
while (removeIter.hasNext()) {
this.collection.remove(removeIter.next());
}
logger.debug(LogMessage.of(() -> "Original collection contained " + originalSize + " elements; now contains "
+ this.collection.size() + " elements"));
return this.collection;
}
@Override
public Iterator<T> iterator() {
return this.collection.iterator();
}
@Override
public void remove(T object) {
this.removeList.add(object);
}
}
@@ -1,21 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* After-invocation providers for collection and array filtering. Consider using a
* {@code PostFilter} annotation in preference.
*/
package org.springframework.security.acls.afterinvocation;
@@ -1,46 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.messaging.access.expression;
import org.springframework.expression.EvaluationContext;
/**
* Allows post processing the {@link EvaluationContext}
*
* <p>
* This API is intentionally kept package scope as it may evolve over time.
* </p>
*
* @author Daniel Bustamante Ospina
* @since 5.2
* @deprecated Since {@link MessageExpressionVoter} is deprecated, there is no more need
* for this class
*/
@Deprecated
interface EvaluationContextPostProcessor<I> {
/**
* Allows post processing of the {@link EvaluationContext}. Implementations may return
* a new instance of {@link EvaluationContext} or modify the {@link EvaluationContext}
* that was passed in.
* @param context the original {@link EvaluationContext}
* @param invocation the security invocation object (i.e. Message)
* @return the updated context.
*/
EvaluationContext postProcess(EvaluationContext context, I invocation);
}
@@ -1,84 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.messaging.access.expression;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.messaging.Message;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.messaging.util.matcher.MessageMatcher;
import org.springframework.util.Assert;
/**
* Simple expression configuration attribute for use in {@link Message} authorizations.
*
* @author Rob Winch
* @author Daniel Bustamante Ospina
* @since 4.0
* @deprecated Use
* {@link org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager}
* instead
*/
@Deprecated
@SuppressWarnings("serial")
class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<Message<?>> {
private final Expression authorizeExpression;
private final MessageMatcher<Object> matcher;
/**
* Creates a new instance
* @param authorizeExpression the {@link Expression} to use. Cannot be null
* @param matcher the {@link MessageMatcher} used to match the messages.
*/
@SuppressWarnings("unchecked")
MessageExpressionConfigAttribute(Expression authorizeExpression, MessageMatcher<?> matcher) {
Assert.notNull(authorizeExpression, "authorizeExpression cannot be null");
Assert.notNull(matcher, "matcher cannot be null");
this.authorizeExpression = authorizeExpression;
this.matcher = (MessageMatcher<Object>) matcher;
}
Expression getAuthorizeExpression() {
return this.authorizeExpression;
}
@Override
public @Nullable String getAttribute() {
return null;
}
@Override
public String toString() {
return this.authorizeExpression.getExpressionString();
}
@Override
public EvaluationContext postProcess(EvaluationContext ctx, Message<?> message) {
Map<String, String> variables = this.matcher.matcher(message).getVariables();
for (Map.Entry<String, String> entry : variables.entrySet()) {
ctx.setVariable(entry.getKey(), entry.getValue());
}
return ctx;
}
}
@@ -1,89 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.messaging.access.expression;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.messaging.Message;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* Voter which handles {@link Message} authorisation decisions. If a
* {@link MessageExpressionConfigAttribute} is found, then its expression is evaluated. If
* true, {@code ACCESS_GRANTED} is returned. If false, {@code ACCESS_DENIED} is returned.
* If no {@code MessageExpressionConfigAttribute} is found, then {@code ACCESS_ABSTAIN} is
* returned.
*
* @author Rob Winch
* @author Daniel Bustamante Ospina
* @since 4.0
* @deprecated Use
* {@link org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager}
* instead
*/
@Deprecated
public class MessageExpressionVoter<T> implements AccessDecisionVoter<Message<T>> {
private SecurityExpressionHandler<Message<T>> expressionHandler = new DefaultMessageSecurityExpressionHandler<>();
@Override
public int vote(Authentication authentication, Message<T> message, Collection<ConfigAttribute> attributes) {
Assert.notNull(authentication, "authentication must not be null");
Assert.notNull(message, "message must not be null");
Assert.notNull(attributes, "attributes must not be null");
MessageExpressionConfigAttribute attr = findConfigAttribute(attributes);
if (attr == null) {
return ACCESS_ABSTAIN;
}
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, message);
ctx = attr.postProcess(ctx, message);
return ExpressionUtils.evaluateAsBoolean(attr.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED;
}
private @Nullable MessageExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attribute : attributes) {
if (attribute instanceof MessageExpressionConfigAttribute) {
return (MessageExpressionConfigAttribute) attribute;
}
}
return null;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof MessageExpressionConfigAttribute;
}
@Override
public boolean supports(Class<?> clazz) {
return Message.class.isAssignableFrom(clazz);
}
public void setExpressionHandler(SecurityExpressionHandler<Message<T>> expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
}
}
@@ -1,117 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access;
import java.util.Collection;
import jakarta.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.util.Assert;
import org.springframework.web.context.ServletContextAware;
/**
* Allows users to determine whether they have privileges for a given web URI.
*
* @author Ben Alex
* @author Luke Taylor
* @since 3.0
* @deprecated Use {@link AuthorizationManagerWebInvocationPrivilegeEvaluator} instead
*/
@Deprecated
public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPrivilegeEvaluator, ServletContextAware {
protected static final Log logger = LogFactory.getLog(DefaultWebInvocationPrivilegeEvaluator.class);
private final AbstractSecurityInterceptor securityInterceptor;
private @Nullable ServletContext servletContext;
public DefaultWebInvocationPrivilegeEvaluator(AbstractSecurityInterceptor securityInterceptor) {
Assert.notNull(securityInterceptor, "SecurityInterceptor cannot be null");
Assert.isTrue(FilterInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
"AbstractSecurityInterceptor does not support FilterInvocations");
Assert.notNull(securityInterceptor.getAccessDecisionManager(),
"AbstractSecurityInterceptor must provide a non-null AccessDecisionManager");
this.securityInterceptor = securityInterceptor;
}
/**
* Determines whether the user represented by the supplied <tt>Authentication</tt>
* object is allowed to invoke the supplied URI.
* @param uri the URI excluding the context path (a default context path setting will
* be used)
*/
@Override
public boolean isAllowed(String uri, @Nullable Authentication authentication) {
return isAllowed(null, uri, null, authentication);
}
/**
* Determines whether the user represented by the supplied <tt>Authentication</tt>
* object is allowed to invoke the supplied URI, with the given .
* <p>
* Note the default implementation of <tt>FilterInvocationSecurityMetadataSource</tt>
* disregards the <code>contextPath</code> when evaluating which secure object
* metadata applies to a given request URI, so generally the <code>contextPath</code>
* is unimportant unless you are using a custom
* <code>FilterInvocationSecurityMetadataSource</code>.
* @param uri the URI excluding the context path
* @param contextPath the context path (may be null, in which case a default value
* will be used).
* @param method the HTTP method (or null, for any method)
* @param authentication the <tt>Authentication</tt> instance whose authorities should
* be used in evaluation whether access should be granted.
* @return true if access is allowed, false if denied
*/
@Override
public boolean isAllowed(@Nullable String contextPath, String uri, @Nullable String method,
@Nullable Authentication authentication) {
Assert.notNull(uri, "uri parameter is required");
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
Collection<ConfigAttribute> attributes = this.securityInterceptor.obtainSecurityMetadataSource()
.getAttributes(filterInvocation);
if (attributes == null) {
return (!this.securityInterceptor.isRejectPublicInvocations());
}
if (authentication == null) {
return false;
}
try {
this.securityInterceptor.getAccessDecisionManager().decide(authentication, filterInvocation, attributes);
return true;
}
catch (AccessDeniedException ex) {
logger.debug(LogMessage.format("%s denied for %s", filterInvocation, authentication), ex);
return false;
}
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
@@ -1,104 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.channel;
import java.io.IOException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.util.Assert;
/**
* @author Luke Taylor
* @deprecated please use
* {@link org.springframework.security.web.transport.HttpsRedirectFilter} and its
* associated {@link PortMapper}
*/
@Deprecated
public abstract class AbstractRetryEntryPoint implements ChannelEntryPoint {
protected final Log logger = LogFactory.getLog(getClass());
private PortMapper portMapper = new PortMapperImpl();
/**
* The scheme ("http://" or "https://")
*/
private final String scheme;
/**
* The standard port for the scheme (80 for http, 443 for https)
*/
private final int standardPort;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public AbstractRetryEntryPoint(String scheme, int standardPort) {
this.scheme = scheme;
this.standardPort = standardPort;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response) throws IOException {
String queryString = request.getQueryString();
String redirectUrl = request.getRequestURI() + ((queryString != null) ? ("?" + queryString) : "");
Integer currentPort = this.portMapper.getServerPort(request);
Integer redirectPort = getMappedPort(currentPort);
if (redirectPort != null) {
boolean includePort = redirectPort != this.standardPort;
String port = (includePort) ? (":" + redirectPort) : "";
redirectUrl = this.scheme + request.getServerName() + port + redirectUrl;
}
this.logger.debug(LogMessage.format("Redirecting to: %s", redirectUrl));
this.redirectStrategy.sendRedirect(request, response, redirectUrl);
}
protected abstract @Nullable Integer getMappedPort(Integer mapFromPort);
protected final PortMapper getPortMapper() {
return this.portMapper;
}
public void setPortMapper(PortMapper portMapper) {
Assert.notNull(portMapper, "portMapper cannot be null");
this.portMapper = portMapper;
}
/**
* Sets the strategy to be used for redirecting to the required channel URL. A
* {@code DefaultRedirectStrategy} instance will be used if not set.
* @param redirectStrategy the strategy instance to which the URL will be passed.
*/
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
Assert.notNull(redirectStrategy, "redirectStrategy cannot be null");
this.redirectStrategy = redirectStrategy;
}
protected final RedirectStrategy getRedirectStrategy() {
return this.redirectStrategy;
}
}
@@ -1,110 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.channel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import jakarta.servlet.ServletException;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* Implementation of {@link ChannelDecisionManager}.
* <p>
* Iterates through each configured {@link ChannelProcessor}. If a
* <code>ChannelProcessor</code> has any issue with the security of the request, it should
* cause a redirect, exception or whatever other action is appropriate for the
* <code>ChannelProcessor</code> implementation.
* <p>
* Once any response is committed (ie a redirect is written to the response object), the
* <code>ChannelDecisionManagerImpl</code> will not iterate through any further
* <code>ChannelProcessor</code>s.
* <p>
* The attribute "ANY_CHANNEL" if applied to a particular URL, the iteration through the
* channel processors will be skipped (see SEC-494, SEC-335).
*
* @author Ben Alex
* @deprecated no replacement is planned, though consider using a custom
* {@link RequestMatcher} for any sophisticated decision-making
*/
@Deprecated
@NullUnmarked
public class ChannelDecisionManagerImpl implements ChannelDecisionManager, InitializingBean {
public static final String ANY_CHANNEL = "ANY_CHANNEL";
private List<ChannelProcessor> channelProcessors;
@Override
public void afterPropertiesSet() {
Assert.notEmpty(this.channelProcessors, "A list of ChannelProcessors is required");
}
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config)
throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (ANY_CHANNEL.equals(attribute.getAttribute())) {
return;
}
}
for (ChannelProcessor processor : this.channelProcessors) {
processor.decide(invocation, config);
if (invocation.getResponse().isCommitted()) {
break;
}
}
}
protected @Nullable List<ChannelProcessor> getChannelProcessors() {
return this.channelProcessors;
}
@SuppressWarnings("cast")
public void setChannelProcessors(List<?> channelProcessors) {
Assert.notEmpty(channelProcessors, "A list of ChannelProcessors is required");
this.channelProcessors = new ArrayList<>(channelProcessors.size());
for (Object currentObject : channelProcessors) {
Assert.isInstanceOf(ChannelProcessor.class, currentObject, () -> "ChannelProcessor "
+ currentObject.getClass().getName() + " must implement ChannelProcessor");
this.channelProcessors.add((ChannelProcessor) currentObject);
}
}
@Override
public boolean supports(ConfigAttribute attribute) {
if (ANY_CHANNEL.equals(attribute.getAttribute())) {
return true;
}
for (ChannelProcessor processor : this.channelProcessors) {
if (processor.supports(attribute)) {
return true;
}
}
return false;
}
}
@@ -1,160 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.channel;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
/**
* Ensures a web request is delivered over the required channel.
* <p>
* Internally uses a {@link FilterInvocation} to represent the request, allowing a
* {@code FilterInvocationSecurityMetadataSource} to be used to lookup the attributes
* which apply.
* <p>
* Delegates the actual channel security decisions and necessary actions to the configured
* {@link ChannelDecisionManager}. If a response is committed by the
* {@code ChannelDecisionManager}, the filter chain will not proceed.
* <p>
* The most common usage is to ensure that a request takes place over HTTPS, where the
* {@link ChannelDecisionManagerImpl} is configured with a {@link SecureChannelProcessor}
* and an {@link InsecureChannelProcessor}. A typical configuration would be
*
* <pre>
*
* &lt;bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter"&gt;
* &lt;property name="channelDecisionManager" ref="channelDecisionManager"/&gt;
* &lt;property name="securityMetadataSource"&gt;
* &lt;security:filter-security-metadata-source request-matcher="regex"&gt;
* &lt;security:intercept-url pattern="\A/secure/.*\Z" access="REQUIRES_SECURE_CHANNEL"/&gt;
* &lt;security:intercept-url pattern="\A/login.jsp.*\Z" access="REQUIRES_SECURE_CHANNEL"/&gt;
* &lt;security:intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/&gt;
* &lt;/security:filter-security-metadata-source&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl"&gt;
* &lt;property name="channelProcessors"&gt;
* &lt;list&gt;
* &lt;ref bean="secureChannelProcessor"/&gt;
* &lt;ref bean="insecureChannelProcessor"/&gt;
* &lt;/list&gt;
* &lt;/property&gt;
* &lt;/bean&gt;
*
* &lt;bean id="secureChannelProcessor"
* class="org.springframework.security.web.access.channel.SecureChannelProcessor"/&gt;
* &lt;bean id="insecureChannelProcessor"
* class="org.springframework.security.web.access.channel.InsecureChannelProcessor"/&gt;
*
* </pre>
*
* which would force the login form and any access to the {@code /secure} path to be made
* over HTTPS.
*
* @author Ben Alex
* @deprecated see {@link org.springframework.security.web.transport.HttpsRedirectFilter}
*/
@Deprecated
public class ChannelProcessingFilter extends GenericFilterBean {
@SuppressWarnings("NullAway.Init")
private ChannelDecisionManager channelDecisionManager;
@SuppressWarnings("NullAway.Init")
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Override
public void afterPropertiesSet() {
Assert.notNull(this.securityMetadataSource, "securityMetadataSource must be specified");
Assert.notNull(this.channelDecisionManager, "channelDecisionManager must be specified");
Collection<ConfigAttribute> attributes = this.securityMetadataSource.getAllConfigAttributes();
if (attributes == null) {
this.logger.warn("Could not validate configuration attributes as the "
+ "FilterInvocationSecurityMetadataSource did not return any attributes");
return;
}
Set<ConfigAttribute> unsupportedAttributes = getUnsupportedAttributes(attributes);
Assert.isTrue(unsupportedAttributes.isEmpty(),
() -> "Unsupported configuration attributes: " + unsupportedAttributes);
this.logger.info("Validated configuration attributes");
}
private Set<ConfigAttribute> getUnsupportedAttributes(Collection<ConfigAttribute> attrDefs) {
Set<ConfigAttribute> unsupportedAttributes = new HashSet<>();
for (ConfigAttribute attr : attrDefs) {
if (!this.channelDecisionManager.supports(attr)) {
unsupportedAttributes.add(attr);
}
}
return unsupportedAttributes;
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
FilterInvocation filterInvocation = new FilterInvocation(request, response, chain);
Collection<ConfigAttribute> attributes = this.securityMetadataSource.getAttributes(filterInvocation);
if (attributes != null) {
this.logger.debug(LogMessage.format("Request: %s; ConfigAttributes: %s", filterInvocation, attributes));
this.channelDecisionManager.decide(filterInvocation, attributes);
@Nullable HttpServletResponse channelResponse = filterInvocation.getResponse();
Assert.notNull(channelResponse, "HttpServletResponse is required");
if (channelResponse.isCommitted()) {
return;
}
}
chain.doFilter(request, response);
}
protected @Nullable ChannelDecisionManager getChannelDecisionManager() {
return this.channelDecisionManager;
}
protected FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
public void setChannelDecisionManager(ChannelDecisionManager channelDecisionManager) {
this.channelDecisionManager = channelDecisionManager;
}
public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) {
this.securityMetadataSource = filterInvocationSecurityMetadataSource;
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.channel;
import java.io.IOException;
import java.util.Collection;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* Ensures channel security is inactive by review of
* <code>HttpServletRequest.isSecure()</code> responses.
* <p>
* The class responds to one case-sensitive keyword, {@link #getInsecureKeyword}. If this
* keyword is detected, <code>HttpServletRequest.isSecure()</code> is used to determine
* the channel security offered. If channel security is present, the configured
* <code>ChannelEntryPoint</code> is called. By default the entry point is
* {@link RetryWithHttpEntryPoint}.
* <p>
* The default <code>insecureKeyword</code> is <code>REQUIRES_INSECURE_CHANNEL</code>.
*
* @author Ben Alex
* @deprecated no replacement is planned, though consider using a custom
* {@link RequestMatcher} for any sophisticated decision-making
*/
@Deprecated
public class InsecureChannelProcessor implements InitializingBean, ChannelProcessor {
private ChannelEntryPoint entryPoint = new RetryWithHttpEntryPoint();
private String insecureKeyword = "REQUIRES_INSECURE_CHANNEL";
@Override
public void afterPropertiesSet() {
Assert.hasLength(this.insecureKeyword, "insecureKeyword required");
Assert.notNull(this.entryPoint, "entryPoint required");
}
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config)
throws IOException, ServletException {
Assert.isTrue(invocation != null && config != null, "Nulls cannot be provided");
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if (invocation.getHttpRequest().isSecure()) {
@Nullable HttpServletResponse response = invocation.getResponse();
Assert.notNull(response, "HttpServletResponse required");
this.entryPoint.commence(invocation.getRequest(), response);
}
}
}
}
public ChannelEntryPoint getEntryPoint() {
return this.entryPoint;
}
public String getInsecureKeyword() {
return this.insecureKeyword;
}
public void setEntryPoint(ChannelEntryPoint entryPoint) {
this.entryPoint = entryPoint;
}
public void setInsecureKeyword(String secureKeyword) {
this.insecureKeyword = secureKeyword;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return (attribute != null) && (attribute.getAttribute() != null)
&& attribute.getAttribute().equals(getInsecureKeyword());
}
}
@@ -1,25 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Classes that ensure web requests are received over required transport channels.
* <p>
* Most commonly used to enforce that requests are submitted over HTTP or HTTPS.
*/
@NullMarked
package org.springframework.security.web.access.channel;
import org.jspecify.annotations.NullMarked;
@@ -1,96 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.expression;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authorization.AuthorizationManagerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
/**
* @author Luke Taylor
* @author Eddú Meléndez
* @author Steve Riesenberg
* @since 3.0
*/
public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation>
implements SecurityExpressionHandler<FilterInvocation> {
private static final String DEFAULT_ROLE_PREFIX = "ROLE_";
private String defaultRolePrefix = DEFAULT_ROLE_PREFIX;
@Override
@SuppressWarnings("deprecation")
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
FilterInvocation fi) {
FilterInvocationExpressionRoot root = new FilterInvocationExpressionRoot(() -> authentication, fi);
root.setAuthorizationManagerFactory(getAuthorizationManagerFactory());
root.setPermissionEvaluator(getPermissionEvaluator());
if (!DEFAULT_ROLE_PREFIX.equals(this.defaultRolePrefix)) {
// Ensure SecurityExpressionRoot can strip the custom role prefix
root.setDefaultRolePrefix(this.defaultRolePrefix);
}
return root;
}
/**
* Sets the {@link AuthenticationTrustResolver} to be used. The default is
* {@link AuthenticationTrustResolverImpl}.
* @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
* null.
* @deprecated Use
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
*/
@Deprecated(since = "7.0")
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
getDefaultAuthorizationManagerFactory().setTrustResolver(trustResolver);
}
/**
* <p>
* Sets the default prefix to be added to
* {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole(String...)}
* or
* {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasRole(String)}.
* For example, if hasRole("ADMIN") or hasRole("ROLE_ADMIN") is passed in, then the
* role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
* </p>
*
* <p>
* If null or empty, then no default role prefix is used.
* </p>
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
* @deprecated Use
* {@link #setAuthorizationManagerFactory(AuthorizationManagerFactory)} instead
*/
@Deprecated(since = "7.0")
public void setDefaultRolePrefix(@Nullable String defaultRolePrefix) {
if (defaultRolePrefix == null) {
defaultRolePrefix = "";
}
getDefaultAuthorizationManagerFactory().setRolePrefix(defaultRolePrefix);
this.defaultRolePrefix = defaultRolePrefix;
}
}
@@ -1,117 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.expression;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* Expression-based {@code FilterInvocationSecurityMetadataSource}.
*
* @author Luke Taylor
* @author Eddú Meléndez
* @since 3.0
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. In the case of
* method security, please see {@link SecurityAnnotationScanner} and
* {@link AuthorizationManager}. In the case of channel security, please see
* {@code HttpsRedirectFilter}. In the case of web security, please see
* {@link AuthorizationManager}.
*/
@Deprecated
public final class ExpressionBasedFilterInvocationSecurityMetadataSource
extends DefaultFilterInvocationSecurityMetadataSource {
private static final Log logger = LogFactory.getLog(ExpressionBasedFilterInvocationSecurityMetadataSource.class);
public ExpressionBasedFilterInvocationSecurityMetadataSource(
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap,
SecurityExpressionHandler<FilterInvocation> expressionHandler) {
super(processMap(requestMap, expressionHandler.getExpressionParser()));
Assert.notNull(expressionHandler, "A non-null SecurityExpressionHandler is required");
}
private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> processMap(
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap, ExpressionParser parser) {
Assert.notNull(parser, "SecurityExpressionHandler returned a null parser object");
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> processed = new LinkedHashMap<>(requestMap);
requestMap.forEach((request, value) -> process(parser, request, value, processed::put));
return processed;
}
private static void process(ExpressionParser parser, RequestMatcher request, Collection<ConfigAttribute> value,
BiConsumer<RequestMatcher, Collection<ConfigAttribute>> consumer) {
String expression = getExpression(request, value);
if (logger.isDebugEnabled()) {
logger.debug(LogMessage.format("Adding web access control expression [%s] for %s", expression, request));
}
AbstractVariableEvaluationContextPostProcessor postProcessor = createPostProcessor(request);
ArrayList<ConfigAttribute> processed = new ArrayList<>(1);
try {
processed.add(new WebExpressionConfigAttribute(parser.parseExpression(expression), postProcessor));
}
catch (ParseException ex) {
throw new IllegalArgumentException("Failed to parse expression '" + expression + "'");
}
consumer.accept(request, processed);
}
private static String getExpression(RequestMatcher request, Collection<ConfigAttribute> value) {
Assert.isTrue(value.size() == 1, () -> "Expected a single expression attribute for " + request);
return value.toArray(new ConfigAttribute[1])[0].getAttribute();
}
private static AbstractVariableEvaluationContextPostProcessor createPostProcessor(RequestMatcher request) {
return new RequestVariablesExtractorEvaluationContextPostProcessor(request);
}
static class RequestVariablesExtractorEvaluationContextPostProcessor
extends AbstractVariableEvaluationContextPostProcessor {
private final RequestMatcher matcher;
RequestVariablesExtractorEvaluationContextPostProcessor(RequestMatcher matcher) {
this.matcher = matcher;
}
@Override
Map<String, String> extractVariables(HttpServletRequest request) {
return this.matcher.matcher(request).getVariables();
}
}
}
@@ -1,70 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.expression;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.web.FilterInvocation;
/**
* Simple expression configuration attribute for use in web request authorizations.
*
* @author Luke Taylor
* @since 3.0
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. Please see
* {@link AuthorizationManager}.
*/
@Deprecated
@NullUnmarked
@SuppressWarnings("serial")
class WebExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<FilterInvocation> {
private final Expression authorizeExpression;
private final EvaluationContextPostProcessor<FilterInvocation> postProcessor;
WebExpressionConfigAttribute(Expression authorizeExpression,
EvaluationContextPostProcessor<FilterInvocation> postProcessor) {
this.authorizeExpression = authorizeExpression;
this.postProcessor = postProcessor;
}
Expression getAuthorizeExpression() {
return this.authorizeExpression;
}
@Override
public EvaluationContext postProcess(EvaluationContext context, FilterInvocation fi) {
return (this.postProcessor != null) ? this.postProcessor.postProcess(context, fi) : context;
}
@Override
public String getAttribute() {
return null;
}
@Override
public String toString() {
return this.authorizeExpression.getExpressionString();
}
}
@@ -1,93 +0,0 @@
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.expression;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.util.Assert;
/**
* Voter which handles web authorisation decisions.
*
* @author Luke Taylor
* @since 3.0
* @deprecated Use {@link WebExpressionAuthorizationManager} instead
*/
@Deprecated
public class WebExpressionVoter implements AccessDecisionVoter<FilterInvocation> {
private final Log logger = LogFactory.getLog(getClass());
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
@Override
public int vote(Authentication authentication, FilterInvocation filterInvocation,
Collection<ConfigAttribute> attributes) {
Assert.notNull(authentication, "authentication must not be null");
Assert.notNull(filterInvocation, "filterInvocation must not be null");
Assert.notNull(attributes, "attributes must not be null");
WebExpressionConfigAttribute webExpressionConfigAttribute = findConfigAttribute(attributes);
if (webExpressionConfigAttribute == null) {
this.logger
.trace("Abstained since did not find a config attribute of instance WebExpressionConfigAttribute");
return ACCESS_ABSTAIN;
}
EvaluationContext ctx = webExpressionConfigAttribute.postProcess(
this.expressionHandler.createEvaluationContext(authentication, filterInvocation), filterInvocation);
boolean granted = ExpressionUtils.evaluateAsBoolean(webExpressionConfigAttribute.getAuthorizeExpression(), ctx);
if (granted) {
return ACCESS_GRANTED;
}
this.logger.trace("Voted to deny authorization");
return ACCESS_DENIED;
}
private @Nullable WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attribute : attributes) {
if (attribute instanceof WebExpressionConfigAttribute) {
return (WebExpressionConfigAttribute) attribute;
}
}
return null;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof WebExpressionConfigAttribute;
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
public void setExpressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
this.expressionHandler = expressionHandler;
}
}
@@ -1,121 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.intercept;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Default implementation of <tt>FilterInvocationDefinitionSource</tt>.
* <p>
* Stores an ordered map of {@link RequestMatcher}s to <tt>ConfigAttribute</tt>
* collections and provides matching of {@code FilterInvocation}s against the items stored
* in the map.
* <p>
* The order of the {@link RequestMatcher}s in the map is very important. The <b>first</b>
* one which matches the request will be used. Later matchers in the map will not be
* invoked if a match has already been found. Accordingly, the most specific matchers
* should be registered first, with the most general matches registered last.
* <p>
* The most common method creating an instance is using the Spring Security namespace. For
* example, the {@code pattern} and {@code access} attributes of the
* {@code <intercept-url>} elements defined as children of the {@code <http>} element are
* combined to build the instance used by the {@code FilterSecurityInterceptor}.
*
* @author Ben Alex
* @author Luke Taylor
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. In the case of
* method security, please see {@link SecurityAnnotationScanner} and
* {@link AuthorizationManager}. In the case of channel security, please see
* {@code HttpsRedirectFilter}. In the case of web security, please see
* {@link AuthorizationManager}.
*/
@Deprecated
public class DefaultFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
protected final Log logger = LogFactory.getLog(getClass());
private final Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;
/**
* Sets the internal request map from the supplied map. The key elements should be of
* type {@link RequestMatcher}, which. The path stored in the key will depend on the
* type of the supplied UrlMatcher.
* @param requestMap order-preserving map of request definitions to attribute lists
*/
public DefaultFilterInvocationSecurityMetadataSource(
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap) {
this.requestMap = requestMap;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
Set<ConfigAttribute> allAttributes = new HashSet<>();
this.requestMap.values().forEach(allAttributes::addAll);
return allAttributes;
}
@Override
public Collection<ConfigAttribute> getAttributes(Object object) {
final HttpServletRequest request = getHttpServletRequest(object);
int count = 0;
for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : this.requestMap.entrySet()) {
if (entry.getKey().matches(request)) {
return entry.getValue();
}
else {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Did not match request to %s - %s (%d/%d)", entry.getKey(),
entry.getValue(), ++count, this.requestMap.size()));
}
}
}
return Collections.emptyList();
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
private HttpServletRequest getHttpServletRequest(Object object) {
if (object instanceof FilterInvocation invocation) {
return invocation.getHttpRequest();
}
if (object instanceof HttpServletRequest request) {
return request;
}
throw new IllegalArgumentException("object must be of type FilterInvocation or HttpServletRequest");
}
}
@@ -1,39 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.intercept;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
import org.springframework.security.web.FilterInvocation;
/**
* Marker interface for <code>SecurityMetadataSource</code> implementations that are
* designed to perform lookups keyed on {@link FilterInvocation}s.
*
* @author Ben Alex
* @deprecated In modern Spring Security APIs, each API manages its own configuration
* context. As such there is no direct replacement for this interface. In the case of
* method security, please see {@link SecurityAnnotationScanner} and
* {@link AuthorizationManager}. In the case of channel security, please see
* {@code HttpsRedirectFilter}. In the case of web security, please see
* {@link AuthorizationManager}.
*/
@Deprecated
public interface FilterInvocationSecurityMetadataSource extends SecurityMetadataSource {
}
@@ -1,149 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.access.intercept;
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
/**
* Performs security handling of HTTP resources via a filter implementation.
* <p>
* The <code>SecurityMetadataSource</code> required by this security interceptor is of
* type {@link FilterInvocationSecurityMetadataSource}.
* <p>
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
* </p>
*
* @author Ben Alex
* @author Rob Winch
* @deprecated Use {@link AuthorizationFilter} instead
*/
@Deprecated
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
private @Nullable FilterInvocationSecurityMetadataSource securityMetadataSource;
private boolean observeOncePerRequest = false;
/**
* Not used (we rely on IoC container lifecycle services instead)
* @param arg0 ignored
*
*/
@Override
public void init(FilterConfig arg0) {
}
/**
* Not used (we rely on IoC container lifecycle services instead)
*/
@Override
public void destroy() {
}
/**
* Method that is actually called by the filter chain. Simply delegates to the
* {@link #invoke(FilterInvocation)} method.
* @param request the servlet request
* @param response the servlet response
* @param chain the filter chain
* @throws IOException if the filter chain fails
* @throws ServletException if the filter chain fails
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
invoke(new FilterInvocation(request, response, chain));
}
public @Nullable FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
@Override
public @Nullable SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
this.securityMetadataSource = newSource;
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {
if (isApplied(filterInvocation) && this.observeOncePerRequest) {
// filter already applied to this request and user wants us to observe
// once-per-request handling, so don't re-do security checking
filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
return;
}
// first time this request being called, so perform security checking
if (filterInvocation.getRequest() != null && this.observeOncePerRequest) {
filterInvocation.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
try {
filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
}
finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, null);
}
private boolean isApplied(FilterInvocation filterInvocation) {
return (filterInvocation.getRequest() != null)
&& (filterInvocation.getRequest().getAttribute(FILTER_APPLIED) != null);
}
/**
* Indicates whether once-per-request handling will be observed. By default this is
* <code>true</code>, meaning the <code>FilterSecurityInterceptor</code> will only
* execute once-per-request. Sometimes users may wish it to execute more than once per
* request, such as when JSP forwards are being used and filter security is desired on
* each included fragment of the HTTP request.
* @return <code>true</code> (the default) if once-per-request is honoured, otherwise
* <code>false</code> if <code>FilterSecurityInterceptor</code> will enforce
* authorizations for each and every fragment of the HTTP request.
*/
public boolean isObserveOncePerRequest() {
return this.observeOncePerRequest;
}
public void setObserveOncePerRequest(boolean observeOncePerRequest) {
this.observeOncePerRequest = observeOncePerRequest;
}
}
@@ -1,55 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.util.SimpleMethodInvocation;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests {@link AuthenticationCredentialsNotFoundEvent}.
*
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class AuthenticationCredentialsNotFoundEventTests {
@Test
public void testRejectsNulls() {
assertThatIllegalArgumentException().isThrownBy(() -> new AuthenticationCredentialsNotFoundEvent(null,
SecurityConfig.createList("TEST"), new AuthenticationCredentialsNotFoundException("test")));
}
@Test
public void testRejectsNulls2() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthenticationCredentialsNotFoundEvent(new SimpleMethodInvocation(), null,
new AuthenticationCredentialsNotFoundException("test")));
}
@Test
public void testRejectsNulls3() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthenticationCredentialsNotFoundEvent(new SimpleMethodInvocation(),
SecurityConfig.createList("TEST"), null));
}
}
@@ -1,79 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.SimpleMethodInvocation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests {@link AuthorizationFailureEvent}.
*
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class AuthorizationFailureEventTests {
private final UsernamePasswordAuthenticationToken foo = UsernamePasswordAuthenticationToken.unauthenticated("foo",
"bar");
private List<ConfigAttribute> attributes = SecurityConfig.createList("TEST");
private AccessDeniedException exception = new AuthorizationServiceException("error", new Throwable());
@Test
public void rejectsNullSecureObject() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthorizationFailureEvent(null, this.attributes, this.foo, this.exception));
}
@Test
public void rejectsNullAttributesList() {
assertThatIllegalArgumentException().isThrownBy(
() -> new AuthorizationFailureEvent(new SimpleMethodInvocation(), null, this.foo, this.exception));
}
@Test
public void rejectsNullAuthentication() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new AuthorizationFailureEvent(new SimpleMethodInvocation(), this.attributes, null,
this.exception));
}
@Test
public void rejectsNullException() {
assertThatIllegalArgumentException().isThrownBy(
() -> new AuthorizationFailureEvent(new SimpleMethodInvocation(), this.attributes, this.foo, null));
}
@Test
public void gettersReturnCtorSuppliedData() {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(new Object(), this.attributes, this.foo,
this.exception);
assertThat(event.getConfigAttributes()).isSameAs(this.attributes);
assertThat(event.getAccessDeniedException()).isSameAs(this.exception);
assertThat(event.getAuthentication()).isSameAs(this.foo);
}
}
@@ -1,53 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.event.AuthorizedEvent;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.SimpleMethodInvocation;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests {@link AuthorizedEvent}.
*
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class AuthorizedEventTests {
@Test
public void testRejectsNulls() {
assertThatIllegalArgumentException().isThrownBy(() -> new AuthorizedEvent(null,
SecurityConfig.createList("TEST"), UsernamePasswordAuthenticationToken.unauthenticated("foo", "bar")));
}
@Test
public void testRejectsNulls2() {
assertThatIllegalArgumentException().isThrownBy(() -> new AuthorizedEvent(new SimpleMethodInvocation(), null,
UsernamePasswordAuthenticationToken.unauthenticated("foo", "bar")));
}
@Test
public void testRejectsNulls3() {
assertThatIllegalArgumentException().isThrownBy(
() -> new AuthorizedEvent(new SimpleMethodInvocation(), SecurityConfig.createList("TEST"), null));
}
}
@@ -1,36 +0,0 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.access;
/**
* Represents the interface of a secured object.
*
* @author Ben Alex
*/
public interface ITargetObject {
Integer computeHashCode(String input);
int countLength(String input);
String makeLowerCase(String input);
String makeUpperCase(String input);
String publicMakeLowerCase(String input);
}

Some files were not shown because too many files have changed in this diff Show More