Skip to content

Commit

Permalink
SHIBUI-1742
Browse files Browse the repository at this point in the history
merged from 1740 code (master)
  • Loading branch information
chasegawa committed Aug 13, 2021
1 parent 4de827b commit b0f5a89
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -559,8 +559,8 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService {
}

public edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver updateMetadataResolverEnabledStatus(edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver updatedResolver) throws ForbiddenException, MetadataFileNotFoundException, InitializationException {
// @TODO: when merged with groups, this should maybe be merged with group check as they have to have the role in the right group
if (!userService.currentUserHasExpectedRole(["ROLE_ADMIN", "ROLE_ENABLE"])) {
if (!userService.currentUserCanEnable(updatedResolver)) {
// if (!userService.currentUserHasExpectedRole(["ROLE_ADMIN", "ROLE_ENABLE"])) {
throw new ForbiddenException("You do not have the permissions necessary to change the enable status of this filter.")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

public enum ActivatableType {
ENTITY_DESCRIPTOR, METADATA_RESOLVER, FILTER
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@
import java.util.UUID;
import java.util.stream.Collectors;

import static edu.internet2.tier.shibboleth.admin.ui.domain.ActivatableType.ENTITY_DESCRIPTOR;

@Entity
@EqualsAndHashCode(callSuper = true)
@Audited
public class EntityDescriptor extends AbstractDescriptor implements org.opensaml.saml.saml2.metadata.EntityDescriptor, Ownable {
public class EntityDescriptor extends AbstractDescriptor implements org.opensaml.saml.saml2.metadata.EntityDescriptor, Ownable, IActivatable {
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "entitydesc_addlmetdatlocations_id")
@OrderColumn
Expand All @@ -47,7 +48,7 @@ public class EntityDescriptor extends AbstractDescriptor implements org.opensaml
@OneToOne(cascade = CascadeType.ALL)
@NotAudited
private AffiliationDescriptor affiliationDescriptor;

@OneToOne(cascade = CascadeType.ALL)
@NotAudited
private AttributeAuthorityDescriptor attributeAuthorityDescriptor;
Expand All @@ -61,7 +62,7 @@ public class EntityDescriptor extends AbstractDescriptor implements org.opensaml
private List<ContactPerson> contactPersons = new ArrayList<>();

private String entityID;

private String localId;

@OneToOne(cascade = CascadeType.ALL)
Expand All @@ -70,7 +71,7 @@ public class EntityDescriptor extends AbstractDescriptor implements org.opensaml
@Getter
@Setter
private String idOfOwner;

@OneToOne(cascade = CascadeType.ALL)
@NotAudited
private PDPDescriptor pdpDescriptor;
Expand Down Expand Up @@ -254,6 +255,10 @@ public void setEntityID(String entityID) {
this.entityID = entityID;
}

public void setEnabled(Boolean serviceEnabled) {
this.serviceEnabled = (serviceEnabled == null) ? false : serviceEnabled;
}

@Override
public void setID(String id) {
this.localId = id;
Expand Down Expand Up @@ -296,12 +301,16 @@ public String toString() {
.add("id", id)
.toString();
}

public String getObjectId() {
return entityID;
}

public OwnableType getOwnableType() {
return OwnableType.ENTITY_DESCRIPTOR;
}
}

@Override public ActivatableType getActivatableType() {
return ENTITY_DESCRIPTOR;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

public interface IActivatable {
ActivatableType getActivatableType();

void setEnabled(Boolean enabled);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable;
import edu.internet2.tier.shibboleth.admin.ui.domain.ActivatableType;
import edu.internet2.tier.shibboleth.admin.ui.domain.IActivatable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -20,6 +22,8 @@
import javax.persistence.Transient;
import java.util.UUID;

import static edu.internet2.tier.shibboleth.admin.ui.domain.ActivatableType.*;

/**
* Domain class to store information about {@link org.opensaml.saml.metadata.resolver.filter.MetadataFilter}
*/
Expand All @@ -38,27 +42,35 @@
@JsonSubTypes.Type(value=NameIdFormatFilter.class, name="NameIDFormat")})
@Audited
@AuditOverride(forClass = AbstractAuditable.class)
public abstract class MetadataFilter extends AbstractAuditable implements IConcreteMetadataFilterType<MetadataFilter> {
public abstract class MetadataFilter extends AbstractAuditable implements IConcreteMetadataFilterType<MetadataFilter>, IActivatable {

@JsonProperty("@type")
@Transient
String type;
private boolean filterEnabled;

private String name;

@Column(unique=true)
private String resourceId = UUID.randomUUID().toString();

private boolean filterEnabled;
@JsonProperty("@type")
@Transient
String type;

@Transient
private transient Integer version;

public ActivatableType getActivatableType() {
return FILTER;
}

@JsonGetter("version")
public int getVersion() {
if (version != null && version != 0) {
return this.version;
}
return this.hashCode();
}
}

public void setEnabled(Boolean serviceEnabled) {
this.filterEnabled = (serviceEnabled == null) ? false : serviceEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable;
import edu.internet2.tier.shibboleth.admin.ui.domain.ActivatableType;
import edu.internet2.tier.shibboleth.admin.ui.domain.IActivatable;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter;
import lombok.EqualsAndHashCode;
Expand All @@ -28,6 +30,8 @@
import java.util.List;
import java.util.UUID;

import static edu.internet2.tier.shibboleth.admin.ui.domain.ActivatableType.*;

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@EqualsAndHashCode(callSuper = true, exclude = {"version", "versionModifiedTimestamp"})
Expand All @@ -43,7 +47,7 @@
@JsonSubTypes.Type(value = ResourceBackedMetadataResolver.class, name = "ResourceBackedMetadataResolver")})
@Audited
@AuditOverride(forClass = AbstractAuditable.class)
public class MetadataResolver extends AbstractAuditable {
public class MetadataResolver extends AbstractAuditable implements IActivatable {

@JsonProperty("@type")
@Transient
Expand Down Expand Up @@ -84,31 +88,35 @@ public class MetadataResolver extends AbstractAuditable {
@Transient
private Integer version;

@JsonGetter("version")
public int getVersion() {
if (this.version != null && this.version != 0 ) {
return this.version;
}
return this.hashCode();
}

public void addFilter(MetadataFilter metadataFilter) {
//To make sure that Spring Data auditing infrastructure recognizes update and "touched" modifiedDate
markAsModified();
this.metadataFilters.add(metadataFilter);
}

public void markAsModified() {
this.versionModifiedTimestamp = System.currentTimeMillis();
}

public void entityAttributesFilterIntoTransientRepresentation() {
//expose explicit API to call to convert into transient representation
//used in unit/integration tests where JPA's @PostLoad callback execution engine is not available
this.metadataFilters
.stream()
.filter(EntityAttributesFilter.class::isInstance)
.map(EntityAttributesFilter.class::cast)
.forEach(EntityAttributesFilter::intoTransientRepresentation);
.stream()
.filter(EntityAttributesFilter.class::isInstance)
.map(EntityAttributesFilter.class::cast)
.forEach(EntityAttributesFilter::intoTransientRepresentation);
}

@Override public ActivatableType getActivatableType() {
return METADATA_RESOLVER;
}

@JsonGetter("version")
public int getVersion() {
if (this.version != null && this.version != 0 ) {
return this.version;
}
return this.hashCode();
}

public void markAsModified() {
this.versionModifiedTimestamp = System.currentTimeMillis();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.*;

import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import edu.internet2.tier.shibboleth.admin.ui.domain.IActivatable;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -25,6 +25,8 @@
import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository;
import lombok.NoArgsConstructor;

import static edu.internet2.tier.shibboleth.admin.ui.security.service.UserAccess.*;

@Service
@NoArgsConstructor
public class UserService {
Expand All @@ -47,10 +49,25 @@ public UserService(IGroupService groupService, OwnershipRepository ownershipRepo
this.userRepository = userRepository;
}

public boolean currentUserCanEnable(IActivatable activatableObject) {
switch (activatableObject.getActivatableType()) {
case ENTITY_DESCRIPTOR: {
if (getCurrentUserAccess() == ADMIN) { return true; }
if (currentUserHasExpectedRole(Arrays.asList("ROLE_ENABLE" )) && getCurrentUserGroup().getOwnerId().equals(((EntityDescriptor) activatableObject).getIdOfOwner())) {
return true;
}
}
case FILTER:
case METADATA_RESOLVER:
return currentUserHasExpectedRole(Arrays.asList("ROLE_ADMIN", "ROLE_ENABLE" ));
}
return false;
}

/**
* Current logic is pretty dumb, this will need to change/expand once a user can have more than one role.
* This basic logic assumes users only have a single role (despite users having a list of roles, we assume only 1 currently)
*/
public boolean currentUserHasExpectedRole(List<String> acceptedRoles) {
private boolean currentUserHasExpectedRole(List<String> acceptedRoles) {
User user = getCurrentUser();
return acceptedRoles.contains(user.getRole());
}
Expand Down Expand Up @@ -91,15 +108,15 @@ public User getCurrentUser() {
public UserAccess getCurrentUserAccess() {
User user = getCurrentUser();
if (user == null) {
return UserAccess.NONE;
return NONE;
}
if (user.getRole().equals("ROLE_ADMIN")) {
return UserAccess.ADMIN;
return ADMIN;
}
if (user.getRole().equals("ROLE_USER")) {
return UserAccess.GROUP;
return GROUP;
}
return UserAccess.NONE;
return NONE;
}

public Group getCurrentUserGroup() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ public EntityDescriptorRepresentation updateEntityDescriptorEnabledStatus(String
if (ed == null) {
throw new EntityNotFoundException("Entity with resourceid[" + resourceId + "] was not found for update");
}
// @TODO: when merged with groups, this should maybe be merged with group check as they have to have the role in the right group
if (!userService.currentUserHasExpectedRole(Arrays.asList(new String[] { "ROLE_ADMIN", "ROLE_ENABLE" }))) {
if (!userService.currentUserCanEnable(ed)) {
// if (!userService.currentUserHasExpectedRole(Arrays.asList(new String[] { "ROLE_ADMIN", "ROLE_ENABLE" }))) {
throw new ForbiddenException("You do not have the permissions necessary to change the enable status of this entity descriptor.");
}
ed.setServiceEnabled(status);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import edu.internet2.tier.shibboleth.admin.ui.domain.IActivatable;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterRepresentation;
Expand Down Expand Up @@ -117,13 +118,13 @@ public MetadataFilter updateFilterEnabledStatus(String metadataResolverId, Strin
if (filterTobeUpdatedOptional.isEmpty()) {
throw new EntityNotFoundException("Filter with resource id[" + resourceId + "] not found");
}

// @TODO: when merged with groups, this should maybe be merged with group check as they have to have the role in the right group
if (!userService.currentUserHasExpectedRole(Arrays.asList(new String[] { "ROLE_ADMIN", "ROLE_ENABLE" }))) {

MetadataFilter filterTobeUpdated = filterTobeUpdatedOptional.get();

if (!userService.currentUserCanEnable(filterTobeUpdated)) {
throw new ForbiddenException("You do not have the permissions necessary to change the enable status of this filter.");
}

MetadataFilter filterTobeUpdated = filterTobeUpdatedOptional.get();

filterTobeUpdated.setFilterEnabled(status);
MetadataFilter persistedFilter = filterRepository.save(filterTobeUpdated);

Expand All @@ -136,4 +137,4 @@ public MetadataFilter updateFilterEnabledStatus(String metadataResolverId, Strin

return persistedFilter;
}
}
}

0 comments on commit b0f5a89

Please sign in to comment.