Skip to content

Commit

Permalink
Merge branch 'security-test' into 'master'
Browse files Browse the repository at this point in the history
Add test submodule for unit/integration testing

See merge request sd/aap/aap-client-java!7
  • Loading branch information
aniewielska committed Feb 10, 2021
2 parents 2207166 + a24a457 commit 1825dc8
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
Expand Down Expand Up @@ -395,9 +397,39 @@ public void can_get_list_of_users_for_domain(){
this.domainsApi.verify();

assertThat(users.size(), is(1));

final User user = users.iterator().next();
assertFalse(user.isAccountNonLocked());
}

/**
* This, as in probably many of these tests, is serving coincidentally as a test of the
* {@code ObjectMapper}'s default forgiving nature, i.e.
* {@code DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES} is disabled!
*/
@Test
public void can_get_list_of_users_for_domain_setting_account_non_locked(){
String domainReference = "domainReference";
String mockResponse = "[ {\n \"userReference\" : \"57d94c6d-565c-46b8-aabe-49c9461fc707\",\n "
+ " \"userName\" : \"946838e27f8831afd866ff6f66ad37f075626ae3\",\n \"email\" :"
+ " \"navispretheeba@gmail.com\",\n \"mobile\" : null,\n \"domains\" : null,\n "
+ " \"accountNonLocked\" : \"true\",\n"
+ "\"links\" : [ {\n \"rel\" : \"self\",\n "
+ " \"href\" : \"https://dev.api.aap.tsi.ebi.ac.uk/users/usr-57d94c6d-565c-46b8-aabe-49c9461fc707\"\n } ]\n} ]";

String expectedUrl = String.format("/domains/dom-%s/users", domainReference);

this.domainsApi.expect(requestTo(expectedUrl)).andExpect(method(HttpMethod.GET))
.andRespond(withSuccess().body(mockResponse).contentType(MediaType.APPLICATION_JSON));

Collection<User> users = subject.getAllUsersFromDomain(domainReference, "token");

this.domainsApi.verify();

assertThat(users.size(), is(1));
final User user = users.iterator().next();
assertTrue(user.isAccountNonLocked());
}

@Test
public void can_get_list_of_managers_for_domain(){

Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ include 'model'
include 'service'
include 'security'

include 'test'
4 changes: 4 additions & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.classpath
/.project
/.settings/
/bin/
3 changes: 3 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# AAP Client Test

This component is for use by AAP developers in their unit and integration test routines.
6 changes: 6 additions & 0 deletions test/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies {
compile ('org.json:json')
compile ('org.springframework.security:spring-security-test')
compile project(':model')
compile project(':security')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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 uk.ac.ebi.tsc.aap.client.test.security.context.support;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.security.test.context.support.WithSecurityContext;

import uk.ac.ebi.tsc.aap.client.test.util.ClientTestUtil;

/**
* Adapted from original Spring work in {@code spring-security-test-4.2.1.RELEASE}.
* <p>
* Behind the scenes the created security context UserDetails will have {@code null}
* values assigned for email, user name and full name.
*
* @author geoff
* @see ClientTestUtil
* @see WithMockAapUserSecurityContextFactory
* @see https://github.com/spring-projects/spring-security/blob/4.2.1.RELEASE/test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithMockAapUserSecurityContextFactory.class)
public @interface WithMockAapUser {
/**
* The username to be used - which <b>MUST</b> be supplied (as per the contract of
* {@code UserDetails#getUsername()}).
* <p>
* Note that for consistency the AAP user reference value should be used, as {@code User#getUsername()}
* (and therefore {@code Authentication#getPrincipal()} returns the user reference.
*
* @return
*/
String username() default "defaultUsername";

/**
* <p>
* The authorities to use. A {@link Domain} will be created for each value.
* </p>
*
* @return
*/
String[] authorities() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed 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 uk.ac.ebi.tsc.aap.client.test.security.context.support;

import java.util.HashSet;
import java.util.Set;

import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithSecurityContextFactory;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils;

import uk.ac.ebi.tsc.aap.client.model.Domain;
import uk.ac.ebi.tsc.aap.client.model.User;
import uk.ac.ebi.tsc.aap.client.security.UserAuthentication;

/**
* Adapted from original Spring work in {@code spring-security-test-4.2.1.RELEASE} to create
* a security context populated with an AAP {@link UserAuthentication} .
*
* @see https://github.com/spring-projects/spring-security/blob/4.2.1.RELEASE/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java
*/
final class WithMockAapUserSecurityContextFactory implements
WithSecurityContextFactory<WithMockAapUser> {

@Override
public SecurityContext createSecurityContext(WithMockAapUser withUser) {
String username = withUser.username();
if (username == null || StringUtils.isEmpty(username)) {
throw new IllegalArgumentException(withUser + " cannot have null or empty username");
}

final Set<Domain> domains = new HashSet<Domain>();
for (String authority : withUser.authorities()) {
domains.add(new Domain(authority, null, null));
}

final User user = new User(null, null, username, null, domains);
// UserAuthentication's initialising constructor is protected, so using reflection
final UserAuthentication authentication = new UserAuthentication();
ReflectionTestUtils.setField(authentication, "user", user);

SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
return context;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package uk.ac.ebi.tsc.aap.client.test.util;

import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

public class ClientJsonUtil {

/**
* Convert the data to a json-format string.
*
* @param data Data to convert.
* @return json representation.
*/
public static String toJson(final Map<String, Object> data) {
if (data == null) {
throw new IllegalArgumentException("Please provide some data to convert to json!");
}

final JSONObject json = new JSONObject();
data.entrySet().stream().forEach(entrySet -> {
try {
json.put(entrySet.getKey(), entrySet.getValue());
} catch (JSONException e) {
throw new UnsupportedOperationException("Error processing JSON " + e.getMessage());
}
});

return json.toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package uk.ac.ebi.tsc.aap.client.test.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.json.JSONException;
import org.json.JSONObject;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import uk.ac.ebi.tsc.aap.client.model.Domain;
import uk.ac.ebi.tsc.aap.client.model.Profile;
import uk.ac.ebi.tsc.aap.client.model.User;
import uk.ac.ebi.tsc.aap.client.test.value.AapClientVersion;

public class ClientTestUtil {

/**
* Authority of AAP admin user.
*/
public static final String AAP_ADMIN_AUTHORITY = "aap.admin";

public enum ErrorResponseProperty {
TIMESTAMP,
STATUS,
ERROR,
MESSAGE,
PATH,
EXCEPTION
}

/**
* Create a json representation of a client user {@link Profile}.
*
* @param version
* @param profileReference
* @param userName
* @param email
* @param userReference
* @param fullName
* @param domains
* @param organization
* @param accountNonLocked
* @param attributes
* @return Json representation.
* @throws JsonProcessingException
*/
public static String createClientUserProfileJson(final AapClientVersion version,
final String profileReference,
final String userName, final String email,
final String userReference, final String fullName,
final Set<Domain> domains, final Object organization,
final boolean accountNonLocked,
final Map<String, String> attributes)
throws JsonProcessingException {
if (version == null) {
throw new IllegalArgumentException("Specify a version!");
}

Profile profile = null;
switch (version) {
case V1_0_6_SNAPSHOT :
case V1_0_7_SNAPSHOT :
/* TODO : This won't help creating legacy json representations if Profile
* structure ever changes because we're using objects! */
final User user = User.builder().withUsername(userName)
.withEmail(email)
.withReference(userReference)
.withFullName(fullName)
.withDomains(domains)
.withAccountNonLocked(accountNonLocked)
.build();
profile = new Profile(profileReference, user, null, attributes);
break;
default :
throw new UnsupportedOperationException("Sorry, version " + version + " not handled yet!");
}
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(profile);
}

/**
* Create the json representation of a {@link User} to pass to the various API endpoints.
* <p>
* {@code Object}s used as args to allow any value (including invalid representations) to be
* sent.
*
* @param version {@code aap-client-java} version to represent.
* @param userName User username
* @param email Email
* @param userReference User reference
* @param fullName Name
* @param organization Organisation
* @param accountNonLocked User account non-locked (only v1.0.7-SNAPSHOT onwards)
* @return Json format of object.
* @see #createUpdateBadUserRegistrationJson()
*/
public static String createClientUserJson(final AapClientVersion version,
final Object userName, final Object email,
final Object userReference, final Object fullName,
final Set<Domain> domains, final Object organization,
final Object accountNonLocked) {
if (version == null) {
throw new IllegalArgumentException("Specify a version!");
}

final Map<String, Object> data = new HashMap<String, Object>();
switch (version) {
case V1_0_6_SNAPSHOT :
if (accountNonLocked != null) {
throw new IllegalArgumentException("accountNonLocked not available in " + version);
}
data.put("userName", userName);
data.put("email", email);
data.put("userReference", userReference);
data.put("fullName", fullName);
data.put("organization", organization);
break;
case V1_0_7_SNAPSHOT :
data.put("userName", userName);
data.put("email", email);
data.put("userReference", userReference);
data.put("fullName", fullName);
data.put("organization", organization);
data.put("accountNonLocked", accountNonLocked);
break;
default :
throw new UnsupportedOperationException("Sorry, version " + version + " not handled yet!");
}
return ClientJsonUtil.toJson(data);
}

/**
* Retrieve the specified property from the AAP-specific {@link ErrorResponse} response.
*
* @param errorResponse Error response.
* @param property Property to extract (the lowercase equivalents are sought).
* @return Extracted property, or {@code null} if no such property available.
*/
public static String retrieveErrorResponseProp(final String errorResponse,
final ErrorResponseProperty property) {
try {
final JSONObject jsonObject = new JSONObject(errorResponse);
return jsonObject.getString(property.toString().toLowerCase());
} catch (JSONException e) {
return null;
}
}
}
Loading

0 comments on commit 1825dc8

Please sign in to comment.