Skip to content

Commit

Permalink
Merge branch 'feature/shibui-1848' of bitbucket.org:unicon/shib-idp-u…
Browse files Browse the repository at this point in the history
…i into feature/shibui-1853
  • Loading branch information
rmathis committed Jun 28, 2021
2 parents 6fb2663 + 3e98da8 commit 8c91f7d
Show file tree
Hide file tree
Showing 23 changed files with 710 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ReloadableMetadat
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects
import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role
import edu.internet2.tier.shibboleth.admin.ui.security.model.User
import edu.internet2.tier.shibboleth.admin.ui.security.repository.GroupsRepository
import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository
import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository
import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions
Expand All @@ -29,6 +31,7 @@ import javax.annotation.PostConstruct
@Profile('dev')
class DevConfig {
private final UserRepository adminUserRepository
private final GroupsRepository groupsRepository
private final RoleRepository roleRepository

private final MetadataResolverRepository metadataResolverRepository
Expand All @@ -37,6 +40,7 @@ class DevConfig {
private final OpenSamlObjects openSamlObjects

DevConfig(UserRepository adminUserRepository,
GroupsRepository groupsRepository,
MetadataResolverRepository metadataResolverRepository,
RoleRepository roleRepository,
EntityDescriptorRepository entityDescriptorRepository,
Expand All @@ -47,11 +51,32 @@ class DevConfig {
this.roleRepository = roleRepository
this.entityDescriptorRepository = entityDescriptorRepository
this.openSamlObjects = openSamlObjects
this.groupsRepository = groupsRepository
}

@Transactional
@PostConstruct
void createDevUsers() {
void createDevUsersAndGroups() {
if (groupsRepository.count() == 0) {
def groups = [
new Group().with {
it.name = "A1"
it.description = "AAA Group"
it.resourceId = "AAA"
it
},
new Group().with {
it.name = "B1"
it.description = "BBB Group"
it.resourceId = "BBB"
it
}]
groups.each {
groupsRepository.save(it)
}
}
groupsRepository.flush()

if (roleRepository.count() == 0) {
def roles = [new Role().with {
name = 'ROLE_ADMIN'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package edu.internet2.tier.shibboleth.admin.ui.security.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.security.service.IGroupService;

@Controller
@RequestMapping(value = "/api/admin/groups")
public class GroupController {
@Autowired
private IGroupService groupService;

@PostMapping
@Transactional
public ResponseEntity<?> create(@RequestBody Group group) {
// If already defined, we can't create a new one, nor will this call update the definition
Group foundGroup = groupService.find(group.getResourceId());

if (foundGroup != null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/groups").build().toUri());

return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value()),
String.format("The group with resource id: [%s] and name: [%s] already exists.",
group.getResourceId(), group.getName())));
}

Group result = groupService.createOrUpdateGroup(group);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

@PutMapping
@Transactional
public ResponseEntity<?> update(@RequestBody Group group) {
Group g = groupService.find(group.getResourceId());

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s] and name: [%s]",
group.getResourceId(), group.getName())));
}

Group result = groupService.createOrUpdateGroup(group);
return ResponseEntity.ok(result);
}

@GetMapping
@Transactional(readOnly = true)
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(groupService.findAll());
}

@GetMapping("/{resourceId}")
@Transactional(readOnly = true)
public ResponseEntity<?> getOne(@PathVariable String resourceId) {
Group g = groupService.find(resourceId);

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s]", resourceId)));
}
return ResponseEntity.ok(g);
}

@DeleteMapping("/{resourceId}")
@Transactional
public ResponseEntity<?> delete(@PathVariable String resourceId) {
Group g = groupService.find(resourceId);

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s]", resourceId)));
}
if (!g.getUsers().isEmpty()) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/admin/groups").build().toUri());

return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()), String.format(
"Unable to delete group with resource id: [%s] - remove all users from group first",
resourceId)));
}
groupService.deleteDefinition(g);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package edu.internet2.tier.shibboleth.admin.ui.security.model;

import java.util.Set;
import java.util.UUID;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import com.fasterxml.jackson.annotation.JsonIgnore;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Entity(name = "user_groups")
@Data
public class Group {
@Column(name = "group_description", nullable = true)
String description;

@Column(nullable = false)
String name;

@Id
@Column(name = "resource_id")
String resourceId = UUID.randomUUID().toString();

@OneToMany(mappedBy = "group", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonIgnore
@EqualsAndHashCode.Exclude
Set<User> users;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
import lombok.ToString;
import org.apache.commons.lang.StringUtils;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.HashSet;
Expand All @@ -30,32 +33,38 @@
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(callSuper = true, exclude = "roles")
@EqualsAndHashCode(callSuper = true)
@ToString(exclude = "roles")
@Table(name = "USERS")
public class User extends AbstractAuditable {

@Column(nullable = false, unique = true)
private String username;

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Column(nullable = false)
private String password;
private String emailAddress;

private String firstName;

@ManyToOne
@JoinColumn(name = "resource_id")
@EqualsAndHashCode.Exclude
private Group group;

private String lastName;

private String emailAddress;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Column(nullable = false)
private String password;

@Transient
private String role;

@JsonIgnore
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@EqualsAndHashCode.Exclude
private Set<Role> roles = new HashSet<>();

@Column(nullable = false, unique = true)
private String username;

public String getRole() {
if (StringUtils.isBlank(this.role)) {
Set<Role> roles = this.getRoles();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.internet2.tier.shibboleth.admin.ui.security.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;

public interface GroupsRepository extends JpaRepository<Group, String> {
List<Group> findAll();

Group findByResourceId(String id);

@SuppressWarnings("unchecked")
Group save(Group group);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
import edu.internet2.tier.shibboleth.admin.ui.security.repository.GroupsRepository;

@Service
public class GroupServiceImpl implements IGroupService {
@Autowired
private GroupsRepository repo;

@Override
public Group createOrUpdateGroup(Group group) {
return repo.save(group);
}

@Override
public void deleteDefinition(Group group) {
repo.delete(group);
}

@Override
public Group find(String resourceId) {
return repo.findByResourceId(resourceId);
}

@Override
public List<Group> findAll() {
return repo.findAll();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.List;

import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;

public interface IGroupService {

Group createOrUpdateGroup(Group g);

void deleteDefinition(Group g);

Group find(String resourceId);

List<Group> findAll();

}
2 changes: 1 addition & 1 deletion backend/src/main/resources/nameid-filter.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"type": "object",
"properties": {
"nameIdFormatFilterTargetType": {
"title": "",
"title": "label.filter-target-type",
"type": "string",
"default": "ENTITY",
"enum": [
Expand Down
Loading

0 comments on commit 8c91f7d

Please sign in to comment.