Skip to content

Commit

Permalink
Merged in feature/SHIBUI-1063 (pull request #285)
Browse files Browse the repository at this point in the history
Feature/SHIBUI-1063
  • Loading branch information
Bill Smith authored and Jonathan Johnson committed Feb 7, 2019
2 parents f6ee403 + 4d6e15e commit 1ab6e41
Show file tree
Hide file tree
Showing 39 changed files with 884 additions and 223 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.internet2.tier.shibboleth.admin.ui.configuration

import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver
Expand All @@ -8,6 +9,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResol
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataQueryProtocolScheme
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ReloadableMetadataResolverAttributes
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.Role
import edu.internet2.tier.shibboleth.admin.ui.security.model.User
Expand All @@ -28,11 +30,13 @@ class DevConfig {
private final RoleRepository roleRepository

private final MetadataResolverRepository metadataResolverRepository
private final EntityDescriptorRepository entityDescriptorRepository

DevConfig(UserRepository adminUserRepository, MetadataResolverRepository metadataResolverRepository, RoleRepository roleRepository) {
DevConfig(UserRepository adminUserRepository, MetadataResolverRepository metadataResolverRepository, RoleRepository roleRepository, EntityDescriptorRepository entityDescriptorRepository) {
this.adminUserRepository = adminUserRepository
this.metadataResolverRepository = metadataResolverRepository
this.roleRepository = roleRepository
this.entityDescriptorRepository = entityDescriptorRepository
}

@Transactional
Expand Down Expand Up @@ -139,4 +143,17 @@ class DevConfig {
return it
})
}

@Profile('ed')
@Transactional
@Bean
EntityDescriptor ed() {
return this.entityDescriptorRepository.save(new EntityDescriptor().with {
it.createdBy = 'nonadmin'
it.entityID = 'testID'
it.serviceEnabled = true
it.serviceProviderName = 'testSP'
it
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ class RelyingPartyOverridesJsonSchemaValidatingControllerAdvice extends RequestB
] as HttpInputMessage
}

@ExceptionHandler(JsonSchemaValidationFailedException)
final ResponseEntity<?> handleJsonSchemaValidationFailedException(JsonSchemaValidationFailedException ex) {
ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse("400", String.join('\n', ex.errors)))
}

@PostConstruct
void init() {
this.jsonSchemaLocation = metadataSourcesSchema(this.jsonSchemaResourceLocationRegistry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
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;
Expand All @@ -30,6 +32,7 @@
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.annotation.PostConstruct;
import javax.xml.ws.Response;
import java.net.URI;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -199,6 +202,28 @@ public ResponseEntity<?> getOneXml(@PathVariable String resourceId) throws Marsh
}
}

@Transactional
@GetMapping(value = "/EntityDescriptor/disabledNonAdmin")
public Iterable<EntityDescriptorRepresentation> getDisabledAndNotOwnedByAdmin() {
return entityDescriptorRepository.findAllDisabledAndNotOwnedByAdmin()
.map(ed -> entityDescriptorService.createRepresentationFromDescriptor(ed))
.collect(Collectors.toList());
}

@Secured("ROLE_ADMIN")
@DeleteMapping(value = "/EntityDescriptor/{resourceId}")
public ResponseEntity<?> deleteOne(@PathVariable String resourceId) {
EntityDescriptor ed = entityDescriptorRepository.findByResourceId(resourceId);
if (ed == null) {
return ResponseEntity.notFound().build();
} else if (ed.isServiceEnabled()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ErrorResponse(HttpStatus.FORBIDDEN, "Deleting an enabled Metadata Source is not allowed. Disable the source and try again."));
} else {
entityDescriptorRepository.delete(ed);
return ResponseEntity.noContent().build();
}
}

private static URI getResourceUriFor(EntityDescriptor ed) {
return ServletUriComponentsBuilder
.fromCurrentServletMapping().path("/api/EntityDescriptor")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse;
import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver;
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaValidationFailedException;
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -12,8 +13,8 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;

import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;

/**
Expand Down Expand Up @@ -56,4 +57,9 @@ public final ResponseEntity<ErrorResponse> metadataFileNotFoundHandler(MetadataF
ErrorResponse errorResponse = new ErrorResponse(INTERNAL_SERVER_ERROR.toString(), ex.getLocalizedMessage());
return new ResponseEntity<>(errorResponse, INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(JsonSchemaValidationFailedException.class)
public final ResponseEntity<?> handleJsonSchemaValidationFailedException(JsonSchemaValidationFailedException ex) {
return ResponseEntity.status(BAD_REQUEST).body(new ErrorResponse("400", String.join("\n", ex.getErrors())));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.jsonschema;

import lombok.Getter;

import java.util.List;

/**
Expand All @@ -8,11 +10,12 @@
*
* @author Dmitriy Kopylenko
*/
class JsonSchemaValidationFailedException extends RuntimeException {
@Getter
public class JsonSchemaValidationFailedException extends RuntimeException {

List<String> errors;

JsonSchemaValidationFailedException(List<String> errors) {
this.errors = errors;
JsonSchemaValidationFailedException(List<?> errors) {
this.errors = (List<String>) errors;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

import java.util.stream.Stream;


/**
* Repository to manage {@link EntityDescriptor} instances.
*/
public interface EntityDescriptorRepository extends CrudRepository<EntityDescriptor, Long> {
public interface EntityDescriptorRepository extends JpaRepository<EntityDescriptor, Long> {

EntityDescriptor findByEntityID(String entityId);

Expand All @@ -21,5 +21,9 @@ public interface EntityDescriptorRepository extends CrudRepository<EntityDescrip
@Query("select e from EntityDescriptor e")
Stream<EntityDescriptor> findAllStreamByCustomQuery();

@Query("select e from EntityDescriptor e, User u join u.roles r " +
"where e.createdBy = u.username and e.serviceEnabled = false and r.name in ('ROLE_USER', 'ROLE_NONE')")
Stream<EntityDescriptor> findAllDisabledAndNotOwnedByAdmin();

Stream<EntityDescriptor> findAllStreamByCreatedBy(String createdBy);
}
4 changes: 4 additions & 0 deletions backend/src/main/resources/i18n/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ label.role=Role
label.delete=Delete?
label.delete-request=Delete Request

label.enable=Enable
label.disable=Disable
label.enable-metadata-sources=Enable Metadata Sources

message.delete-user-title=Delete User?
message.delete-user-body=You are requesting to delete a user. If you complete this process the user will be removed. This cannot be undone. Do you wish to continue?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export enum AdminCollectionActionTypes {
UPDATE_ADMIN_SUCCESS = '[Admin Collection] Update Admin Success',
UPDATE_ADMIN_FAIL = '[Admin Collection] Update Admin Fail',

LOAD_NEW_USERS_REQUEST = '[Admin Collection] Load New Users Request',
LOAD_ADMIN_REQUEST = '[Admin Collection] Load Admin Request',
LOAD_ADMIN_SUCCESS = '[Admin Collection] Load Admin Success',
LOAD_ADMIN_ERROR = '[Admin Collection] Load Admin Error',
Expand Down Expand Up @@ -52,12 +51,6 @@ export class LoadAdminRequest implements Action {
constructor() { }
}

export class LoadNewUsersRequest implements Action {
readonly type = AdminCollectionActionTypes.LOAD_NEW_USERS_REQUEST;

constructor() { }
}

export class LoadAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.LOAD_ADMIN_SUCCESS;

Expand Down Expand Up @@ -133,7 +126,6 @@ export type AdminCollectionActionsUnion =
| LoadAdminRequest
| LoadAdminSuccess
| LoadAdminError
| LoadNewUsersRequest
| AddAdminRequest
| AddAdminSuccess
| AddAdminFail
Expand Down
90 changes: 90 additions & 0 deletions ui/src/app/admin/action/metadata-collection.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Action } from '@ngrx/store';
import { MetadataResolver } from '../../metadata/domain/model';
import { Update } from '@ngrx/entity';

export enum MetadataCollectionActionTypes {
UPDATE_METADATA_REQUEST = '[Admin Metadata Collection] Update Request',
UPDATE_METADATA_SUCCESS = '[Admin Metadata Collection] Update Success',
UPDATE_METADATA_FAIL = '[Admin Metadata Collection] Update Fail',
UPDATE_METADATA_CONFLICT = '[Admin Metadata Collection] Update Conflict',

LOAD_METADATA_REQUEST = '[Admin Metadata Collection] Load Metadata REQUEST',
LOAD_METADATA_SUCCESS = '[Admin Metadata Collection] Load Metadata SUCCESS',
LOAD_METADATA_ERROR = '[Admin Metadata Collection] Load Metadata ERROR',

REMOVE_METADATA = '[Admin Metadata Collection] Remove Metadata',
REMOVE_METADATA_SUCCESS = '[Admin Metadata Collection] Remove Metadata Success',
REMOVE_METADATA_FAIL = '[Admin Metadata Collection] Remove Metadata Fail',
}

export class LoadMetadataRequest implements Action {
readonly type = MetadataCollectionActionTypes.LOAD_METADATA_REQUEST;

constructor() { }
}

export class LoadMetadataSuccess implements Action {
readonly type = MetadataCollectionActionTypes.LOAD_METADATA_SUCCESS;

constructor(public payload: MetadataResolver[]) { }
}

export class LoadMetadataError implements Action {
readonly type = MetadataCollectionActionTypes.LOAD_METADATA_ERROR;

constructor(public payload: any) { }
}

export class UpdateMetadataRequest implements Action {
readonly type = MetadataCollectionActionTypes.UPDATE_METADATA_REQUEST;

constructor(public payload: MetadataResolver) { }
}

export class UpdateMetadataSuccess implements Action {
readonly type = MetadataCollectionActionTypes.UPDATE_METADATA_SUCCESS;

constructor(public payload: Update<MetadataResolver>) { }
}

export class UpdateMetadataFail implements Action {
readonly type = MetadataCollectionActionTypes.UPDATE_METADATA_FAIL;

constructor(public payload: any) { }
}

export class UpdateMetadataConflict implements Action {
readonly type = MetadataCollectionActionTypes.UPDATE_METADATA_CONFLICT;

constructor(public payload: MetadataResolver) { }
}

export class RemoveMetadataRequest implements Action {
readonly type = MetadataCollectionActionTypes.REMOVE_METADATA;

constructor(public payload: MetadataResolver) { }
}

export class RemoveMetadataSuccess implements Action {
readonly type = MetadataCollectionActionTypes.REMOVE_METADATA_SUCCESS;

constructor(public payload: MetadataResolver) { }
}

export class RemoveMetadataFail implements Action {
readonly type = MetadataCollectionActionTypes.REMOVE_METADATA_FAIL;

constructor(public payload: MetadataResolver) { }
}

export type MetadataCollectionActionsUnion =
| LoadMetadataRequest
| LoadMetadataSuccess
| LoadMetadataError
| RemoveMetadataRequest
| RemoveMetadataSuccess
| RemoveMetadataFail
| UpdateMetadataRequest
| UpdateMetadataSuccess
| UpdateMetadataFail
| UpdateMetadataConflict;
12 changes: 11 additions & 1 deletion ui/src/app/admin/admin.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { AdminComponent } from './admin.component';
import { RouterTestingModule } from '@angular/router/testing';
import { StoreModule, combineReducers, Store } from '@ngrx/store';
import * as fromAdmin from './reducer';

describe('Admin Root Component', () => {
let fixture: ComponentFixture<AdminComponent>;
let instance: AdminComponent;
let store: Store<fromAdmin.State>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
RouterTestingModule,
StoreModule.forRoot({
admin: combineReducers(fromAdmin.reducers)
})
],
declarations: [
AdminComponent
],
});

store = TestBed.get(Store);
spyOn(store, 'dispatch');

fixture = TestBed.createComponent(AdminComponent);
instance = fixture.componentInstance;
});
Expand All @@ -24,5 +33,6 @@ describe('Admin Root Component', () => {
fixture.detectChanges();

expect(fixture).toBeDefined();
expect(store.dispatch).toHaveBeenCalled();
});
});
10 changes: 9 additions & 1 deletion ui/src/app/admin/admin.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { Component } from '@angular/core';

import * as fromRoot from '../app.reducer';
import { Store } from '@ngrx/store';
import { LoadAdminRequest } from './action/admin-collection.action';

@Component({
selector: 'admin-page',
templateUrl: './admin.component.html',
styleUrls: []
})
export class AdminComponent {
constructor() { }
constructor(
private store: Store<fromRoot.State>
) {
this.store.dispatch(new LoadAdminRequest());
}
}
Loading

0 comments on commit 1ab6e41

Please sign in to comment.