Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.jspecify.annotations.Nullable;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
Expand All @@ -34,7 +35,8 @@
* @author Ben Alex
* @author Scott Battaglia
*/
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
public class CasAuthenticationToken extends AbstractAuthenticationToken
implements BuildableAuthentication, Serializable {

private static final long serialVersionUID = 620L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.jspecify.annotations.Nullable;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

Expand All @@ -32,7 +33,8 @@
* @author Hal Deadman
* @since 6.1
*/
public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationToken {
public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationToken
implements BuildableAuthentication {

static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.jspecify.annotations.Nullable;

import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

Expand All @@ -32,7 +33,7 @@
* @author Ben Alex
* @author Luke Taylor
*/
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements BuildableAuthentication {

private static final long serialVersionUID = 620L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import org.jspecify.annotations.Nullable;

import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.util.Assert;
Expand All @@ -34,7 +35,7 @@
*
* @author Ben Alex
*/
public class TestingAuthenticationToken extends AbstractAuthenticationToken {
public class TestingAuthenticationToken extends AbstractAuthenticationToken implements BuildableAuthentication {

private static final long serialVersionUID = 1L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.jspecify.annotations.Nullable;

import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

Expand All @@ -35,7 +36,8 @@
* @author Ben Alex
* @author Norbert Nowak
*/
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken
implements BuildableAuthentication {

private static final long serialVersionUID = 620L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.jspecify.annotations.Nullable;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.BuildableAuthentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

Expand All @@ -31,7 +32,7 @@
* @author Josh Cummings
* @since 7.0
*/
public class OneTimeTokenAuthentication extends AbstractAuthenticationToken {
public class OneTimeTokenAuthentication extends AbstractAuthenticationToken implements BuildableAuthentication {

@Serial
private static final long serialVersionUID = 1195893764725073959L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.jspecify.annotations.Nullable;

Expand Down Expand Up @@ -138,35 +140,37 @@ public interface Authentication extends Principal, Serializable {
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;

/**
* Return an {@link Builder} based on this instance. By default, returns a builder
* that builds a {@link SimpleAuthentication}.
* <p>
* Although a {@code default} method, all {@link Authentication} implementations
* should implement this. The reason is to ensure that the {@link Authentication} type
* is preserved when {@link Builder#build} is invoked. This is especially important in
* the event that your authentication implementation contains custom fields.
* </p>
* <p>
* This isn't strictly necessary since it is recommended that applications code to the
* {@link Authentication} interface and that custom information is often contained in
* the {@link Authentication#getPrincipal} value.
* </p>
* @return an {@link Builder} for building a new {@link Authentication} based on this
* instance
* @since 7.0
*/
default Builder<?> toBuilder() {
return new SimpleAuthentication.Builder(this);
}

/**
* A builder based on a given {@link Authentication} instance
* A builder based on a given {@link BuildableAuthentication} instance
*
* @author Josh Cummings
* @since 7.0
*/
interface Builder<B extends Builder<B>> {

/**
* Apply this authentication instance
* <p>
* By default, merges the authorities in the provided {@code authentication} with
* the authentication being built. Only those authorities that haven't already
* been specified to the builder will be added.
* </p>
* @param authentication the {@link Authentication} to appluy
* @return the {@link Builder} for additional configuration
* @see BuildableAuthentication#getAuthorities
*/
default B authentication(Authentication authentication) {
return authorities((a) -> {
Set<String> newAuthorities = a.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toUnmodifiableSet());
for (GrantedAuthority currentAuthority : authentication.getAuthorities()) {
if (!newAuthorities.contains(currentAuthority.getAuthority())) {
a.add(currentAuthority);
}
}
});
}

/**
* Mutate the authorities with this {@link Consumer}.
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.core;

/**
* An {@link Authentication} that is also buildable.
*
* @author Josh Cummings
* @since 7.0
*/
public interface BuildableAuthentication extends Authentication {

/**
* Return an {@link Builder} based on this instance.
* <p>
* Although a {@code default} method, all {@link BuildableAuthentication}
* implementations should implement this. The reason is to ensure that the
* {@link BuildableAuthentication} type is preserved when {@link Builder#build} is
* invoked. This is especially important in the event that your authentication
* implementation contains custom fields.
* </p>
* <p>
* This isn't strictly necessary since it is recommended that applications code to the
* {@link Authentication} interface and that custom information is often contained in
* the {@link Authentication#getPrincipal} value.
* </p>
* @return an {@link Builder} for building a new {@link Authentication} based on this
* instance
*/
Builder<?> toBuilder();

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ void applyWhenAuthoritiesThenAdds() {
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
}

@Test
void authenticationWhenAuthoritiesThenAdds() {
TestingAuthenticationToken factorOne = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE");
TestingAuthenticationToken factorTwo = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO");
TestAbstractAuthenticationBuilder builder = new TestAbstractAuthenticationBuilder(factorOne);
Authentication result = builder.authentication(factorTwo).build();
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
}

private static final class TestAbstractAuthenticationBuilder
extends TestingAuthenticationToken.Builder<TestAbstractAuthenticationBuilder> {

Expand Down
Loading