diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/DevConfig.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/DevConfig.groovy index e9e530d64..78c250823 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/DevConfig.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/DevConfig.groovy @@ -34,16 +34,27 @@ class DevConfig { @Transactional @PostConstruct - void createDevAdminUsers() { + void createDevUsers() { if (adminUserRepository.count() == 0) { - def user = new User().with { + def users = [new User().with { username = 'admin' password = '{noop}adminpass' + name = 'Joe the admin' + emailAddress = 'joe@institution.edu' roles.add(new Role(name: 'ROLE_ADMIN')) it + }, new User().with { + username = 'nonadmin' + password = '{noop}nonadminpass' + name = 'Peter non admin' + emailAddress = 'peter@institution.edu' + roles.add(new Role(name: 'ROLE_USER')) + it + }] + users.each { + adminUserRepository.save(it) } - adminUserRepository.save(user) } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersController.java new file mode 100644 index 000000000..ab0127ce5 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersController.java @@ -0,0 +1,30 @@ +package edu.internet2.tier.shibboleth.admin.ui.security.controller; + +import edu.internet2.tier.shibboleth.admin.ui.security.model.User; +import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * Implementation of the REST resource endpoints exposing system users. + * + * @author Dmitriy Kopylenko + */ +@RestController +@RequestMapping("/api/security/users") +public class UsersController { + + private UserRepository userRepository; + + public UsersController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping + List getAll() { + return userRepository.findAll(); + } + } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Role.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Role.java index 20564093d..fcb893c20 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Role.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/Role.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.security.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -31,6 +32,8 @@ public class Role extends AbstractAuditable { @Column(unique = true) private String name; + //Ignore properties annotation here is to prevent stack overflow recursive error during JSON serialization + @JsonIgnoreProperties("roles") @ManyToMany(cascade = CascadeType.ALL, mappedBy = "roles", fetch = FetchType.EAGER) private Set users = new HashSet<>(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/User.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/User.java index 9b24cf946..55ecd40b8 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/User.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/security/model/User.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.security.model; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; import lombok.*; @@ -33,11 +34,12 @@ public class User extends AbstractAuditable { @Column(nullable = false) private String password; - private String firstName; + private String name; - private String lastName; + private String emailAddress; - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + //Ignore properties annotation here is to prevent stack overflow recursive error during JSON serialization + @JsonIgnoreProperties("users") @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) private Set roles = new HashSet<>(); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy new file mode 100644 index 000000000..6b2c5f2cc --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy @@ -0,0 +1,30 @@ +package edu.internet2.tier.shibboleth.admin.ui.security.controller + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.test.context.ActiveProfiles +import spock.lang.Specification + +/** + * @author Dmitriy Kopylenko + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles(["no-auth", "dev"]) +class UsersControllerIntegrationTests extends Specification { + + @Autowired + private TestRestTemplate restTemplate + + static RESOURCE_URI = '/api/security/users' + + def "GET users"() { + when: 'GET request is made for ALL users in the system' + def result = this.restTemplate.getForEntity(RESOURCE_URI, Object) + + then: "Request completed successfully" + result.statusCodeValue == 200 + result.body[0].username == 'admin' + result.body[0].roles[0].name == 'ROLE_ADMIN' + } +} \ No newline at end of file