SEC-717: Resolve UserDetails.getAuthorities() sort logic issue.
This commit is contained in:
parent
820c529809
commit
6bc0585e4a
|
@ -17,6 +17,8 @@ package org.springframework.security;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Represents an authority granted to an {@link Authentication} object.
|
||||
*
|
||||
|
@ -26,10 +28,16 @@ import java.io.Serializable;
|
|||
* AccessDecisionManager}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementations must implement {@link Comparable} in order to ensure that
|
||||
* array sorting logic guaranteed by {@link UserDetails#getAuthorities()} can
|
||||
* be reliably implemented.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface GrantedAuthority extends Serializable {
|
||||
public interface GrantedAuthority extends Serializable, Comparable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,8 @@ package org.springframework.security;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Basic concrete implementation of a {@link GrantedAuthority}.<p>Stores a <code>String</code> representation of an
|
||||
|
@ -35,6 +37,7 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
|||
|
||||
public GrantedAuthorityImpl(String role) {
|
||||
super();
|
||||
Assert.hasText(role, "A granted authority textual representation is required");
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
|
@ -65,4 +68,12 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
|
|||
public String toString() {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
public int compareTo(Object o) {
|
||||
if (o != null && o instanceof GrantedAuthority) {
|
||||
GrantedAuthority rhs = (GrantedAuthority) o;
|
||||
return this.role.compareTo(rhs.getAuthority());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
|
||||
package org.springframework.security.userdetails;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import java.util.Iterator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
|
@ -231,13 +234,15 @@ public class User implements UserDetails {
|
|||
|
||||
protected void setAuthorities(GrantedAuthority[] authorities) {
|
||||
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority array");
|
||||
|
||||
// Ensure array iteration order is predictable (as per UserDetails.getAuthorities() contract and SEC-xxx)
|
||||
SortedSet sorter = new TreeSet();
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
Assert.notNull(authorities[i],
|
||||
"Granted authority element " + i + " is null - GrantedAuthority[] cannot contain any null elements");
|
||||
sorter.add(authorities[i]);
|
||||
}
|
||||
|
||||
this.authorities = authorities;
|
||||
this.authorities = (GrantedAuthority[]) sorter.toArray(new GrantedAuthority[sorter.size()]);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
|
|
@ -54,7 +54,7 @@ public interface UserDetails extends Serializable {
|
|||
/**
|
||||
* Returns the authorities granted to the user. Cannot return <code>null</code>.
|
||||
*
|
||||
* @return the authorities (never <code>null</code>)
|
||||
* @return the authorities, sorted by natural key (never <code>null</code>)
|
||||
*/
|
||||
GrantedAuthority[] getAuthorities();
|
||||
|
||||
|
|
|
@ -76,14 +76,18 @@ public class GrantedAuthorityImplTests extends TestCase {
|
|||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockGrantedAuthorityImpl implements GrantedAuthority {
|
||||
private class MockGrantedAuthorityImpl implements GrantedAuthority, Comparable {
|
||||
private String role;
|
||||
|
||||
public MockGrantedAuthorityImpl(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
private MockGrantedAuthorityImpl() {
|
||||
public int compareTo(Object o) {
|
||||
return this.role.compareTo(((GrantedAuthority)o).getAuthority());
|
||||
}
|
||||
|
||||
private MockGrantedAuthorityImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,11 @@ public class UserTests extends TestCase {
|
|||
new User("rod", "koala", true, true, true, true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")})));
|
||||
|
||||
// Equal as the new User will internally sort the GrantedAuthorities in the correct order, before running equals()
|
||||
assertTrue(user1.equals(
|
||||
new User("rod", "koala", true, true, true, true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TWO"), new GrantedAuthorityImpl("ROLE_ONE")})));
|
||||
|
||||
assertFalse(user1.equals(
|
||||
new User("DIFFERENT_USERNAME", "koala", true, true, true, true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")})));
|
||||
|
@ -153,7 +158,7 @@ public class UserTests extends TestCase {
|
|||
|
||||
public void testUserGettersSetter() throws Exception {
|
||||
UserDetails user = new User("rod", "koala", true, true, true, true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TWO"), new GrantedAuthorityImpl("ROLE_ONE")});
|
||||
assertEquals("rod", user.getUsername());
|
||||
assertEquals("koala", user.getPassword());
|
||||
assertTrue(user.isEnabled());
|
||||
|
|
Loading…
Reference in New Issue