Skip to content

Commit

Permalink
Makes user mutable with the option to make immutable (#40)
Browse files Browse the repository at this point in the history
Makes user mutable with the option to make immutable.
  • Loading branch information
Travis Tomsu committed Jun 6, 2016
1 parent ffc028b commit c956378
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,41 @@ package com.netflix.spinnaker.security

import com.fasterxml.jackson.annotation.JsonIgnore
import groovy.transform.Immutable
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails

/**
* User implements UserDetails in order to properly hook into the Spring Security framework.
*/
@Immutable
class User implements Serializable, UserDetails {
class User implements UserDetails {
static final long serialVersionUID = 7392392099262597885L

String email
String username
String firstName
String lastName

Collection<String> roles
Collection<String> roles = []
Collection<String> allowedAccounts = []

@Override
List getAuthorities() {
roles?.collect { new SimpleGrantedAuthority(it) }
roles.collect { new SimpleGrantedAuthority(it) }
}

String username = email
@Override
String getUsername() {
return this.username ?: this.email
}

ImmutableUser asImmutable() {
new ImmutableUser()
}

/** Not used **/
@JsonIgnore String password
@JsonIgnore
final String password = ""

@Override
boolean isAccountNonExpired() { return true }
Expand All @@ -56,4 +65,17 @@ class User implements Serializable, UserDetails {

@Override
boolean isEnabled() { return true }

@Immutable
class ImmutableUser extends User {
String email = User.this.email
String username = User.this.username
String firstName = User.this.firstName
String lastName = User.this.lastName

// Use .collect() to snapshot these collections.
Collection<String> roles = User.this.roles.collect()
Collection<String> allowedAccounts = User.this.allowedAccounts.collect()
List<GrantedAuthority> authorities = User.this.authorities.collect()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2016 Google, Inc.
*
* 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
*
* http://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 com.netflix.spinnaker.security

import spock.lang.Specification

class UserSpec extends Specification {

def "should not reflect changes to the mutable user in the immutable user"() {
setup:
def accounts = ["abc"]
def mutableUser = new User(email: "email", allowedAccounts: accounts)
def immutableUser = mutableUser.asImmutable()

expect:
mutableUser.email == "email"
mutableUser.allowedAccounts == ["abc"]
immutableUser.email == "email"
immutableUser.username == "email"
immutableUser.allowedAccounts == ["abc"]

when:
mutableUser.email = "batman"
accounts.add("def")

then:
mutableUser.email == "batman"
mutableUser.allowedAccounts == ["abc", "def"]
immutableUser.email == "email"
immutableUser.allowedAccounts == ["abc"]

when:
mutableUser.allowedAccounts = ["xyz"]

then:
mutableUser.allowedAccounts == ["xyz"]
immutableUser.allowedAccounts == ["abc"]
}

def "should fallback to email if no username is set"() {
setup:
def user = new User(email: "email")

expect:
user.email == "email"
user.username == "email"

when:
user.username = "username"

then:
user.username == "username"
}
}

0 comments on commit c956378

Please sign in to comment.