Increment to 6.5.0-SNAPSHOT

Closes gh-16221
This commit is contained in:
Rob Winch 2024-12-12 21:44:08 -06:00
parent 7e83fd54aa
commit 2fcd305509
13 changed files with 5225 additions and 404 deletions

View File

@ -4,6 +4,31 @@ registries:
type: maven-repository
url: https://repo.spring.io/milestone
updates:
- package-ecosystem: gradle
target-branch: 6.4.x
directory: /
schedule:
interval: daily
time: '03:00'
timezone: Etc/UTC
labels:
- 'type: dependency-upgrade'
registries:
- spring-milestones
ignore:
- dependency-name: com.nimbusds:nimbus-jose-jwt
- dependency-name: org.python:jython
- dependency-name: org.apache.directory.server:*
- 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: gradle
target-branch: 6.3.x
directory: /
@ -58,6 +83,16 @@ updates:
update-types:
- version-update:semver-major
- package-ecosystem: github-actions
target-branch: 6.4.x
directory: /
schedule:
interval: weekly
labels:
- 'type: task'
- 'in: build'
ignore:
- dependency-name: sjohnr/*
- package-ecosystem: github-actions
target-branch: 6.3.x
directory: /
@ -66,6 +101,8 @@ updates:
labels:
- 'type: task'
- 'in: build'
ignore:
- dependency-name: sjohnr/*
- package-ecosystem: github-actions
target-branch: main
directory: /

View File

@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
# List of active maintenance branches.
branch: [ main, 6.3.x, 6.2.x, 5.8.x ]
branch: [ main, 6.4.x, 6.3.x, 6.2.x, 5.8.x ]
runs-on: ubuntu-latest
steps:
- name: Checkout

View File

@ -96,7 +96,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
pc.getReaderContext()
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or "
+ "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
+ "with Spring Security 6.4. Please update your schema declarations to the 6.4 schema.",
+ "with Spring Security 6.5. Please update your schema declarations to the 6.5 schema.",
element);
}
String name = pc.getDelegate().getLocalName(element);
@ -221,7 +221,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-6\\.4.*.xsd.*")
return schemaLocation.matches("(?m).*spring-security-6\\.5.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}

View File

@ -14,7 +14,8 @@
# limitations under the License.
#
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.4.xsd
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd
http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
http\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
http\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd
http\://www.springframework.org/schema/security/spring-security-6.2.xsd=org/springframework/security/config/spring-security-6.2.xsd
@ -40,7 +41,8 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.4.xsd
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
https\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd
https\://www.springframework.org/schema/security/spring-security-6.2.xsd=org/springframework/security/config/spring-security-6.2.xsd

View File

@ -65,7 +65,7 @@ public class XsdDocumentedTests {
String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
String schemaDocumentLocation = "org/springframework/security/config/spring-security-6.4.xsd";
String schemaDocumentLocation = "org/springframework/security/config/spring-security-6.5.xsd";
XmlSupport xml = new XmlSupport();
@ -151,8 +151,8 @@ public class XsdDocumentedTests {
.list((dir, name) -> name.endsWith(".xsd"));
// @formatter:on
assertThat(schemas.length)
.withFailMessage("the count is equal to 26, if not then schemaDocument needs updating")
.isEqualTo(26);
.withFailMessage("the count is equal to 27, if not then schemaDocument needs updating")
.isEqualTo(27);
}
/**

View File

@ -22,7 +22,7 @@
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security org/springframework/security/config/spring-security-6.4.xsd">
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
<tx:annotation-driven />

View File

@ -6,4 +6,4 @@ This appendix provides a reference to the elements available in the security nam
If you haven't used the namespace before, please read the xref:servlet/configuration/xml-namespace.adoc#ns-config[introductory chapter] on namespace configuration, as this is intended as a supplement to the information there.
Using a good quality XML editor while editing a configuration based on the schema is recommended as this will provide contextual information on which elements and attributes are available as well as comments explaining their purpose.
The namespace is written in https://relaxng.org/[RELAX NG] Compact format and later converted into an XSD schema.
If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/main/config/src/main/resources/org/springframework/security/config/spring-security-6.4.rnc[schema file] directly.
If you are familiar with this format, you may wish to examine the https://raw.githubusercontent.com/spring-projects/spring-security/main/config/src/main/resources/org/springframework/security/config/spring-security-6.5.rnc[schema file] directly.

View File

@ -1,394 +1,5 @@
[[new]]
= What's New in Spring Security 6.4
= What's New in Spring Security 6.5
Spring Security 6.4 provides a number of new features.
Spring Security 6.5 provides a number of new features.
Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix.
== Deprecation Notices
As we get closer to Spring Security 7, it's important to stay up to date on deprecations.
As such, this section points out deprecations in the 6.4 release.
* *Method Security* - `AuthorizationManager#check` is deprecated in favor of `AuthorizationManager#authorize`.
This is primarily to allow the return type to be an interface instead of a concrete class.
If you are invoking `AuthorizationManager#check`, please invoke `AuthorizationManager#authorize` instead.
+
Relatedly, `AuthorizationEventPublisher#publishEvent` that takes an `AuthorizationDecision` is deprecated in favor of a method of the same name that takes an `AuthorizationResult` interface instead.
* *Method Security* - `PrePostTemplateDefaults` is deprecated in favor of the more generic `AnnotationTemplateExpressionDefaults` as there is now meta-annotation property support for `@AuthenticationPrincipal` and `@CurrentSecurityContext` as well.
If you are constructing a `PrePostTemplateDefaults`, change this out for an `AnnotationTemplateExpressionDefaults`.
* *OAuth 2.0* - `NimbusOpaqueTokenIntrospector` has been deprecated in favor of `SpringOpaqueTokenIntrospector` in order to remove Spring Security OAuth 2.0 Resource Server's reliance on the `oidc-oauth2-sdk` package.
If you are constructing a `NimbusOpaqueTokenIntrospector`, replace it with ``SpringOpaqueTokenIntrospector``'s constructor
* *OAuth 2.0* - `DefaultAuthorizationCodeTokenResponseClient`, `DefaultClientCredentialsTokenResponseClient`, `DefaultJwtBearerTokenResponseClient`, `DefaultPasswordTokenResponseClient`, `DefaultRefreshTokenTokenResponseClient`, and `DefaultTokenExchangeTokenResponseClient` are deprecated in favor of their `RestClient` equivalents.
+
Relatedly,`JwtBearerGrantRequestEntityConverter`, `OAuth2AuthorizationCodeGrantRequestEntityConverter`, `OAuth2ClientCredentialsGrantRequestEntityConverter`, `OAuth2PasswordGrantRequestEntityConverter`, `OAuth2RefreshTokenGrantRequestEntityConverter` are deprecated in favor of providing an instance of `DefaultOAuth2TokenRequestParametersConverter` to one of the above token response clients
+
For example, if you have the following arrangement:
+
[source,java]
----
private static class MyCustomConverter
extends AbstractOAuth2AuthorizationGrantRequestEntityConverter<OAuth2AuthorizationCodeGrantRequest> {
@Override
protected MultiValueMap<String, String> createParameters
(OAuth2AuthorizationCodeGrantRequest request) {
MultiValueMap<String, String> parameters = super.createParameters(request);
parameters.add("custom", "value");
return parameters;
}
}
@Bean
OAuth2AccessTokenResponseClient authorizationCode() {
DefaultAuthorizationCodeTokenResponseClient client =
new DefaultAuthorizationCodeTokenResponseClient();
Converter<AuthorizationCodeGrantRequest, RequestEntity<?>> entityConverter =
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
entityConverter.setParametersConverter(new MyCustomConverter());
client.setRequestEntityConverter(entityConverter);
return client;
}
----
+
This configuration is deprecated since it uses `DefaultAuthorizationCodeTokenResponseClient` and `OAuth2AuthorizationCodeGrantRequestEntityConverter`.
The recommended configuration is now:
+
[source,java]
----
private static class MyCustomConverter implements Converter<OAuth2AuthorizationCodeGrantRequest, Map<String, String>> {
@Override
public MultiValueMap<String, String> convert(OAuth2AuthorizeCodeGrantRequest request) {
MultiValueMap<String, String> parameters = OAuth2AuthorizationCodeGrantRequest.defaultParameters(request);
parameters.add("custom", "value");
return parameters;
}
}
@Bean
OAuth2AccessTokenResponseClient authorizationCode() {
RestClientAuthorizationCodeTokenResponseClient client =
new RestClientAuthorizationCodeTokenResponseClient();
client.setParametersConverter(new MyCustomConverter());
return client;
}
----
* *SAML 2.0* - Unversioned OpenSAML implementations of Spring Security SAML 2.0 Service Provider's interfaces have been deprecated in favor of versioned ones.
For example, `OpenSamlAuthenticationTokenConverter` is now replaced by `OpenSaml4AuthenticationTokenConverter` and `OpenSaml5AuthenticationTokenConverter`.
If you are constructing one of these deprecated versions, please replace it with the one that corresponds to the OpenSAML version you are using.
* *SAML 2.0* - Methods surrounding `AssertingPartyDetails` are deprecated in favor of equivalent methods that use the `AssertingPartyMetadata` interface.
* *LDAP* - Usages of `DistinguishedName` are now deprecated in order to align with Spring LDAP's deprecations
== One-Time Token Login
* Spring Security now xref:servlet/authentication/onetimetoken.adoc[supports One-Time Token Login] via the `oneTimeTokenLogin()` DSL, including xref:servlet/authentication/onetimetoken.adoc#customize-generate-consume-token[JDBC support].
== Passkeys
Spring Security now has xref:servlet/authentication/passkeys.adoc[Passkeys] support.
== Method Security
* All xref:servlet/authorization/method-security.adoc#meta-annotations[method security annotations] now support {spring-framework-api-url}org/springframework/core/annotation/AliasFor.html[Framework's `@AliasFor`]
* `@AuthenticationPrincipal` and `@CurrentSecurityContext` now support xref:servlet/authorization/method-security.adoc#_templating_meta_annotation_expressions[annotation templates].
+
This means that you can now use Spring's meta-annotation support like so:
+
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Target(TargetType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal("claims['{claim}']")
@interface CurrentUsername {
String claim() default "sub";
}
// ...
@GetMapping
public String method(@CurrentUsername("username") String username) {
// ...
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
annotation CurrentUsername(val claim: String = "sub")
// ...
@GetMapping
fun method(@CurrentUsername("username") val username: String): String {
// ...
}
----
======
* https://github.com/spring-projects/spring-security/issues/13490[Several] https://github.com/spring-projects/spring-security/issues/13234[improvements] https://github.com/spring-projects/spring-security/issues/15097[were made] to align Security's annotation search with ``AbstractFallbackMethodSecurityMetadataSource``'s algorithm.
This aids in migration from earlier versions of Spring Security.
* Native applications can now xref:servlet/authorization/method-security.adoc#authorize-return-object-aot[use `@AuthorizeReturnObject`]
* Native applications can now xref:servlet/authorization/method-security.adoc#pre-post-authorize-aot[reference beans in `@PreAuthorize` and `@PostAuthorize`]
* `SecurityAnnotationScanners` offers https://github.com/spring-projects/spring-security/issues/15700[a convenient API] for scanning for Security annotations and for adding Security's selection and templating features to custom annotations
== OAuth 2.0
* `oauth2Login()` now accepts https://github.com/spring-projects/spring-security/pull/15237[`OAuth2AuthorizationRequestResolver` as a `@Bean`]
* `ClientRegistrations` now supports externally obtained configuration
* Added `loginPage()` to DSL in reactive `oauth2Login()`
* OIDC Back-Channel support now accepts https://github.com/spring-projects/spring-security/issues/15003[logout tokens of type `logout+jwt`]
* `RestClient` can now be xref:servlet/oauth2/index.adoc#oauth2-client-access-protected-resources[configured] with `OAuth2ClientHttpRequestInterceptor` to xref:servlet/oauth2/index.adoc#oauth2-client-accessing-protected-resources-example[make protected resources requests]
* Added `RestClient`-based implementations of `OAuth2AccessTokenResponseClient` for more consistent configuration of access token requests.
+
To opt-in to using `RestClient` support, simply publish a bean for each grant type as in the following example:
+
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
return new RestClientAuthorizationCodeTokenResponseClient();
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
return new RestClientRefreshTokenTokenResponseClient();
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
return new RestClientClientCredentialsTokenResponseClient();
}
@Bean
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
return new RestClientJwtBearerTokenResponseClient();
}
@Bean
public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() {
return new RestClientTokenExchangeTokenResponseClient();
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Configuration
class SecurityConfig {
@Bean
fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
return RestClientAuthorizationCodeTokenResponseClient()
}
@Bean
fun refreshTokenAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
return RestClientRefreshTokenTokenResponseClient()
}
@Bean
fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
return RestClientClientCredentialsTokenResponseClient()
}
@Bean
fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
return RestClientJwtBearerTokenResponseClient()
}
@Bean
fun tokenExchangeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
return RestClientTokenExchangeTokenResponseClient()
}
}
----
======
* Token Exchange now https://github.com/spring-projects/spring-security/issues/15534[supports refresh tokens]
== SAML 2.0
* Added xref:servlet/saml2/opensaml.adoc[OpenSAML 5 Support].
Now you can use either OpenSAML 4 or OpenSAML 5; by default, Spring Security will select the right implementations based on what's on your classpath.
* Using EntityIDs for the `registrationId` is simplified.
+
A common pattern is to identify asserting parties by their `entityID`.
In previous versions, this required directly configuring `OpenSamlAuthenticationRequestResolver`.
Now, the request resolver looks by default for the `registrationId` https://github.com/spring-projects/spring-security/issues/15017[as a request parameter] in addition to looking for it in the path.
This allows you to use `RelyingPartyRegistrations` or `OpenSaml4/5AssertingPartyMetadataRepository` without also needing to modify the `registrationId` values or customize the request resolver.
+
Relatedly, you can now configure your `authenticationRequestUri` to xref:servlet/saml2/login/authentication-requests.adoc#configuring-authentication-request-uri[contain a query parameter]
* Asserting Parties can now be refreshed in the background according to the metadata's expiry.
+
For example, you can now use xref:servlet/saml2/metadata.adoc#using-assertingpartymetadatarepository[`OpenSaml5AssertingPartyMetadataRepository`] to do:
+
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Component
public class RefreshableRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository {
private final AssertingPartyMetadataRepository assertingParties = OpenSaml5AssertingPartyMetadataRepository
.fromTrustedMetadataLocation("https://idp.example.org").build();
@Override
public RelyingPartyRegistration findByRegistrationId(String registrationId) {
AssertingPartyMetadata assertingParty = this.assertingParties.findByEntityId(registrationId);
return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty)
// relying party configurations
.build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Component
open class RefreshableRelyingPartyRegistrationRepository: IterableRelyingPartyRegistrationRepository {
private val assertingParties: AssertingPartyMetadataRepository = OpenSaml5AssertingPartyMetadataRepository
.fromTrustedMetadataLocation("https://idp.example.org").build()
override fun findByRegistrationId(String registrationId): RelyingPartyRegistration {
val assertingParty = this.assertingParties.findByEntityId(registrationId)
return RelyingPartyRegistration.withAssertingPartyMetadata(assertingParty)
// relying party configurations
.build()
}
// ...
}
----
======
+
This implementation also supports the validation of a metadata's signature.
* You can now sign https://github.com/spring-projects/spring-security/pull/14916[relying party metadata]
* `RelyingPartyRegistrationRepository` results can now be javadoc:org.springframework.security.saml2.provider.service.registration.CachingRelyingPartyRegistrationRepository[cached].
This is helpful if you want to defer the loading of the registration values til after application startup.
It is also helpful if you want to control when metadata gets refreshed via Spring Cache.
* To align with the SAML 2.0 standard, the metadata endpoint now https://github.com/spring-projects/spring-security/issues/15147[uses the `application/samlmetadata+xml` MIME type]
== Web
* CSRF BREACH tokens are now https://github.com/spring-projects/spring-security/issues/15187[more consistent]
* The Remember Me cookie now is https://github.com/spring-projects/spring-security/pull/15203[more customizable]
* Security Filter Chain finds more invalid configurations.
For example, a filter chain declared after an any-request filter chain is invalid since it will never be invoked:
+
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
@Order(0)
SecurityFilterChain api(HttpSecurity http) throws Exception {
http
// implicit securityMatcher("/**")
.authorizeHttpRequests(...)
.httpBasic(...)
return http.build();
}
@Bean
@Order(1)
SecurityFilterChain app(HttpSecurity http) throws Exception {
http
.securityMatcher("/app/**")
.authorizeHttpRequests(...)
.formLogin(...)
return http.build();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
@Order(0)
fun api(val http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
// ...
}
}
return http.build()
}
@Bean
@Order(1)
fun app(val http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/app/**")
authorizeHttpRequests {
// ...
}
}
return http.build()
}
----
======
You can read more https://github.com/spring-projects/spring-security/issues/15220[in the related ticket].
* `ServerHttpSecurity` now https://github.com/spring-projects/spring-security/issues/15974[picks up `ServerWebExchangeFirewall` as a `@Bean`]
== Observability
Observability now supports xref:servlet/integrations/observability.adoc#observability-tracing-disable[toggling authorization, authentication, and request observations separately]
For example, to turn off filter chain observations, you can publish a `@Bean` like this one:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
SecurityObservationSettings allSpringSecurityObservations() {
return SecurityObservationSettings.withDefaults()
.shouldObserveFilterChains(false).build();
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun allSpringSecurityObservations(): SecurityObservationSettings {
return SecurityObservationSettings.builder()
.shouldObserveFilterChains(false).build()
}
----
======
== Kotlin
* The Kotlin DSL now supports https://github.com/spring-projects/spring-security/issues/14935[SAML 2.0] and https://github.com/spring-projects/spring-security/issues/15171[`GrantedAuthorityDefaults`] and https://github.com/spring-projects/spring-security/issues/15136[`RoleHierarchy`] ``@Bean``s
* `@PreFilter` and `@PostFilter` are https://github.com/spring-projects/spring-security/pull/15095[now supported] in Kotlin
* The Kotlin Reactive DSL now supports https://github.com/spring-projects/spring-security/pull/15013[`SecurityContextRepository`]
== Acl
* `AclAuthorizationStrategyImpl` now https://github.com/spring-projects/spring-security/issues/4186[supports `RoleHierarchy`]

View File

@ -4,7 +4,7 @@ require 'net/http'
require 'yaml'
require 'logger'
$main_branch = "6.4.x"
$main_branch = "6.5.x"
$log = Logger.new(STDOUT)
$log.level = Logger::WARN

View File

@ -14,7 +14,7 @@
# limitations under the License.
#
springBootVersion=3.3.3
version=6.4.2-SNAPSHOT
version=6.5.0-SNAPSHOT
samplesBranch=main
org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true

View File

@ -20,7 +20,7 @@
version="2.0">
<description>Spring Security Authorization Tag Library</description>
<tlib-version>6.4</tlib-version>
<tlib-version>6.5</tlib-version>
<short-name>security</short-name>
<uri>http://www.springframework.org/security/tags</uri>