Skip to content

Commit cdcb38f

Browse files
committed
Add Expirable Authorities
Allowing individual authorities to expire offers enormous flexibility as far as granting authorities that need to be renewed independently from logging in.
1 parent 5c2a977 commit cdcb38f

File tree

5 files changed

+88
-3
lines changed

5 files changed

+88
-3
lines changed

config/src/test/java/org/springframework/security/SerializationSamples.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
import org.springframework.security.core.Authentication;
9393
import org.springframework.security.core.GrantedAuthority;
9494
import org.springframework.security.core.authority.AuthorityUtils;
95+
import org.springframework.security.core.authority.ExpirableGrantedAuthority;
9596
import org.springframework.security.core.context.SecurityContext;
9697
import org.springframework.security.core.context.SecurityContextImpl;
9798
import org.springframework.security.core.context.TransientSecurityContext;
@@ -375,6 +376,8 @@ final class SerializationSamples {
375376
generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message"));
376377

377378
// core
379+
generatorByClassName.put(ExpirableGrantedAuthority.class,
380+
(r) -> new ExpirableGrantedAuthority("a", Instant.now()));
378381
generatorByClassName.put(RunAsUserToken.class, (r) -> {
379382
RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(),
380383
AnonymousAuthenticationToken.class);

core/src/main/java/org/springframework/security/authorization/AuthoritiesAuthorizationManager.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.util.Collection;
2020
import java.util.HashSet;
21-
import java.util.List;
2221
import java.util.Set;
2322
import java.util.function.Supplier;
2423

@@ -90,10 +89,16 @@ public AuthorizationResult authorize(Supplier<Authentication> authentication, Co
9089
}
9190

9291
private Collection<GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
92+
Collection<GrantedAuthority> authorities = new HashSet<>();
9393
if (authentication == null) {
94-
return List.of();
94+
return authorities;
9595
}
96-
return new HashSet<>(this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities()));
96+
for (GrantedAuthority authority : authentication.getAuthorities()) {
97+
if (authority.isGranted()) {
98+
authorities.add(authority);
99+
}
100+
}
101+
return new HashSet<>(this.roleHierarchy.getReachableGrantedAuthorities(authorities));
97102
}
98103

99104
}

core/src/main/java/org/springframework/security/core/GrantedAuthority.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ public interface GrantedAuthority extends Serializable {
4848
*/
4949
String getAuthority();
5050

51+
default boolean isGranted() {
52+
return true;
53+
}
54+
5155
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.core.authority;
18+
19+
import java.io.Serial;
20+
import java.time.Clock;
21+
import java.time.Instant;
22+
import java.util.Objects;
23+
24+
import org.springframework.security.core.GrantedAuthority;
25+
import org.springframework.util.Assert;
26+
27+
public final class ExpirableGrantedAuthority implements GrantedAuthority {
28+
29+
@Serial
30+
private static final long serialVersionUID = 4168993944484835205L;
31+
32+
private final String authority;
33+
34+
private final Instant expiresAt;
35+
36+
private Clock clock = Clock.systemUTC();
37+
38+
public ExpirableGrantedAuthority(String authority, Instant expiresAt) {
39+
Assert.notNull(authority, "authority cannot be null");
40+
Assert.notNull(expiresAt, "expiresAt cannot be null");
41+
this.authority = authority;
42+
this.expiresAt = expiresAt;
43+
}
44+
45+
@Override
46+
public String getAuthority() {
47+
return this.authority;
48+
}
49+
50+
@Override
51+
public boolean isGranted() {
52+
return this.clock.instant().isAfter(this.expiresAt);
53+
}
54+
55+
public void setClock(Clock clock) {
56+
Assert.notNull(clock, "clock cannot be null");
57+
this.clock = clock;
58+
}
59+
60+
@Override
61+
public boolean equals(Object o) {
62+
if (!(o instanceof GrantedAuthority that)) {
63+
return false;
64+
}
65+
return Objects.equals(this.authority, that.getAuthority());
66+
}
67+
68+
@Override
69+
public int hashCode() {
70+
return Objects.hashCode(this.authority);
71+
}
72+
73+
}

0 commit comments

Comments
 (0)