Skip to content

Commit

Permalink
Merged in feature/shibui-1747 (pull request #529)
Browse files Browse the repository at this point in the history
Feature/shibui 1747

Approved-by: Jonathan Johnson
Approved-by: Bill Smith
  • Loading branch information
chasegawa authored and Jonathan Johnson committed Oct 1, 2021
2 parents 50ab5e7 + b2de75b commit a23980f
Show file tree
Hide file tree
Showing 44 changed files with 2,140 additions and 1,176 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// This code is based on:
//
// com.thoughtworks.selenium.webdriven.commands.AttachFile
//
// in Selenium WebDriver.
//
// The following copyright is copied from original.
// ---
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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 jp.vmi.selenium.selenese.command;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.io.FilenameUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.io.TemporaryFilesystem;

import com.google.common.io.Resources;

import jp.vmi.selenium.selenese.Context;
import jp.vmi.selenium.selenese.result.Error;
import jp.vmi.selenium.selenese.result.Result;
import jp.vmi.selenium.selenese.result.Warning;

import static jp.vmi.selenium.selenese.command.ArgumentType.*;
import static jp.vmi.selenium.selenese.result.Success.*;

/**
* Re-implementation of AttachFile.
*/
public class AttachFile extends AbstractCommand {

private static final int ARG_LOCATOR = 0;
private static final int ARG_FILENAME = 1;

AttachFile(int index, String name, String... args) {
super(index, name, args, LOCATOR, VALUE);
}

@Override
protected Result executeImpl(Context context, String... curArgs) {
String name = curArgs[ARG_FILENAME];
File outputTo = null;
if (name.contains("://")) {
// process (remote) url
URL url;
try {
url = new URL(name);
} catch (MalformedURLException e) {
return new Error("Malformed URL: " + name);
}
File dir = TemporaryFilesystem.getDefaultTmpFS().createTempDir("attachFile", "dir");
outputTo = new File(dir, new File(url.getFile()).getName());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outputTo);
Resources.copy(url, fos);
} catch (IOException e) {
return new Error("Can't access file to upload: " + url, e);
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
return new Warning("Unable to close stream used for reading file: " + name, e);
}
}
} else {
// process file besides testcase file
// okay, let's fix some cases...
if (name.matches("([a-zA-Z]:)?\\\\.+")) {
// windows absolute path
outputTo = new File(name);
} else {
outputTo = new File(FilenameUtils.getPath(context.getCurrentTestCase().getFilename()), name);
}
if (!outputTo.exists()) {
return new Error("Can't access file: " + outputTo);
}
}

WebElement element = context.findElement(curArgs[ARG_LOCATOR]);
try {
element.clear();
} catch (Exception e) {
// ignore exceptions from some drivers when file-input cannot be cleared;
}
element.sendKeys(outputTo.getAbsolutePath());
return SUCCESS;
}
}
11 changes: 7 additions & 4 deletions backend/src/integration/resources/SHIBUI-1744-2.side
Original file line number Diff line number Diff line change
Expand Up @@ -367,14 +367,14 @@
"id": "c82be982-6551-4d50-af85-b9e87610e000",
"comment": "",
"command": "waitForElementVisible",
"target": "css=fieldset > ul > li > strong",
"target": "css=fieldset > div > button > strong",
"targets": [],
"value": "Bundle - Test Bundle"
}, {
"id": "e3b80e89-4278-4e2e-9aa4-d2cc03e86932",
"comment": "",
"command": "assertText",
"target": "css=fieldset > ul > li > strong",
"target": "css=fieldset > div > button > strong",
"targets": [
["css=strong", "css:finder"],
["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/ul/li/strong", "xpath:idRelative"],
Expand All @@ -386,9 +386,12 @@
"id": "421fdaa5-e42b-4ba3-be22-c5697624ee34",
"comment": "",
"command": "click",
"target": "css=.fa-check:nth-child(2)",
"target": "css=fieldset > div > button",
"targets": [
["css=.fa-check:nth-child(2)", "css:finder"]
["css=.badge-light", "css:finder"],
["xpath=//div[@id='root']/div/main/div/section/div[2]/div[2]/div/div/form/div/div/div/div/div[10]/div/div/fieldset/div/button/span", "xpath:idRelative"],
["xpath=//div/button/span", "xpath:position"],
["xpath=//span[contains(.,'Select Bundle')]", "xpath:innerText"]
],
"value": ""
}, {
Expand Down
15 changes: 11 additions & 4 deletions backend/src/integration/resources/SHIBUI-1744-3.side
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,14 @@
"id": "e8a2f501-0efa-43a3-bbf2-b86e5ec8f6d1",
"comment": "",
"command": "waitForElementVisible",
"target": "css=fieldset > ul > li > strong",
"target": "css=fieldset > div > button > strong",
"targets": [],
"value": "30000"
}, {
"id": "cc36c580-3d53-483a-a813-2a6c8fb95792",
"comment": "",
"command": "assertText",
"target": "css=fieldset > ul > li > strong",
"target": "css=fieldset > div > button > strong",
"targets": [
["css=strong", "css:finder"],
["xpath=//div[@id='root']/div/main/div/section/div[2]/div/div[2]/div[2]/div[2]/div/form/div/div/div/div[8]/div/div/div/fieldset/ul/li/strong", "xpath:idRelative"],
Expand All @@ -473,7 +473,7 @@
"id": "caabc3c1-7ac7-4251-9885-fe2e3b7c4c10",
"comment": "",
"command": "click",
"target": "css=fieldset > ul > li > button",
"target": "css=fieldset > div > button",
"targets": [
["css=.fa-check:nth-child(2) > path", "css:finder"]
],
Expand Down Expand Up @@ -623,11 +623,18 @@
["xpath=//button[contains(.,' Save')]", "xpath:innerText"]
],
"value": ""
}, {
"id": "e54aff89-0f95-452f-92c0-42ca78188fc0",
"comment": "",
"command": "waitForElementVisible",
"target": "css=#filters > ul > li > div > button",
"targets": [],
"value": "30000"
}, {
"id": "d6a2d477-4b89-4cf5-a4a8-0f35afcdd5f8",
"comment": "",
"command": "click",
"target": "css=.mx-4",
"target": "css=#filters > ul > li > div > button",
"targets": [
["css=.mx-4", "css:finder"],
["xpath=(//button[@type='button'])[13]", "xpath:attributes"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public class WebSecurityConfig {

@Bean
@Profile("!no-auth")
public AdminUserService adminUserService(UserRepository userRepository) {
return new AdminUserService(userRepository);
public AdminUserService adminUserService(UserService userService) {
return new AdminUserService(userService);
}

private HttpFirewall allowUrlEncodedSlashHttpFirewall() {
Expand Down Expand Up @@ -128,7 +128,7 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
.password(defaultPassword)
.roles("ADMIN");
}
auth.userDetailsService(adminUserService(userRepository)).passwordEncoder(passwordEncoder);
auth.userDetailsService(adminUserService(userService)).passwordEncoder(passwordEncoder);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,15 @@ public String getOwnerId() {
public OwnerType getOwnerType() {
return OwnerType.USER;
}


/**
* @return the FIRST role found for the user or an exception if the user has no roles
*/
public String getRole() {
if (StringUtils.isBlank(this.role)) {
Set<Role> roles = this.getRoles();
if (roles.size() != 1) {
throw new RuntimeException(String.format("User with username [%s] has no role or does not have exactly one role!", this.getUsername()));
if (roles.isEmpty()) {
throw new RuntimeException(String.format("User with username [%s] has no roles", this.getUsername()));
}
this.role = roles.iterator().next().getName();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

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

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.RoleDeleteException;
Expand All @@ -11,12 +13,17 @@ public interface IRolesService {

Role createRole(Role role) throws RoleExistsConflictException;

Role updateRole(Role role) throws EntityNotFoundException;

List<Role> findAll();

Optional<Role> findByName(String roleNone);

Role findByResourceId(String resourceId) throws EntityNotFoundException;

Set<Role> getAndCreateAllRoles(Set<String> roles);

void deleteDefinition(String resourceId) throws EntityNotFoundException, RoleDeleteException;

}
Role updateRole(Role role) throws EntityNotFoundException;

void save(Role newUserRole);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand All @@ -15,7 +17,7 @@
@Service
public class RolesServiceImpl implements IRolesService {
@Autowired
private RoleRepository roleRepository;
RoleRepository roleRepository;

@Override
public Role createRole(Role role) throws RoleExistsConflictException {
Expand All @@ -42,6 +44,11 @@ public List<Role> findAll() {
return roleRepository.findAll();
}

@Override
public Optional<Role> findByName(String roleName) {
return roleRepository.findByName(roleName);
}

@Override
public Role findByResourceId(String resourceId) throws EntityNotFoundException {
Optional<Role> found = roleRepository.findByResourceId(resourceId);
Expand All @@ -51,6 +58,30 @@ public Role findByResourceId(String resourceId) throws EntityNotFoundException {
return found.get();
}

@Override
public Set<Role> getAndCreateAllRoles(Set<String> roleNames) {
HashSet<Role> result = new HashSet<>();
if (roleNames == null || roleNames.isEmpty()) {
Role r = getRoleNone();
result.add(r);
return result;
}
roleNames.forEach(roleName -> {
Optional<Role> role = roleRepository.findByName(roleName);
result.add(role.orElseGet(() -> roleRepository.save(new Role(roleName))));
});
return result;
}

private Role getRoleNone() {
Optional<Role> noRole = roleRepository.findByName("ROLE_NONE");
if (noRole.isEmpty()) {
Role newUserRole = new Role("ROLE_NONE");
return roleRepository.save(newUserRole);
}
return noRole.get();
}

@Override
public Role updateRole(Role role) throws EntityNotFoundException {
Optional<Role> found = roleRepository.findByName(role.getName());
Expand All @@ -59,4 +90,9 @@ public Role updateRole(Role role) throws EntityNotFoundException {
}
return roleRepository.save(role);
}
}

@Override
public void save(Role newUserRole) {
roleRepository.save(newUserRole);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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.UserRepository;
import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
Expand All @@ -22,12 +22,12 @@
@RequiredArgsConstructor
public class AdminUserService implements UserDetailsService {

private final UserRepository userRepository;
private final UserService userService;

@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository
User user = userService
.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException(String.format("User [%s] is not found", username)));

Expand All @@ -43,5 +43,4 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx

return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}

}
3 changes: 3 additions & 0 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
# forceServiceProviderMetadataGeneration: false
# callbackUrl: "https://localhost:8443/callback"
# maximumAuthenticationLifetime: 3600000
# requireAssertedRoleForNewUsers: false
# saml2ProfileMapping:
# username: urn:oid:0.9.2342.19200300.100.1.1
# firstname: urn:oid:2.5.4.42
# lastname: urn:oid:2.5.4.4
# email: urn:oid:0.9.2342.19200300.100.1.3
# groups: urn:oid:1.3.6.1.4.1.5923.1.5.1.1 # attributeId - isMemberOf
# roles: --define name of the attribute containing the incoming user roles--

custom:
attributes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ class AdminUserServiceTests extends AbstractBaseDataJpaTest {
@TestConfiguration
private static class AUSLocalConfig {
@Bean
AdminUserService adminUserService(UserRepository userRepository) {
return new AdminUserService(userRepository)
AdminUserService adminUserService(UserService userService) {
return new AdminUserService(userService)
}

// Rather than having a specific dev context needed, we just stand up the needed bean.
Expand Down
Loading

0 comments on commit a23980f

Please sign in to comment.