Commit 83c093c0 authored by Daniel Scholl's avatar Daniel Scholl
Browse files

Merge branch 'eleckner/us/2181' into 'master'

Eleckner/us/2181

See merge request !9
parents be7dc41b de2e7f77
Pipeline #2880 passed with stages
in 13 minutes and 8 seconds
......@@ -67,6 +67,16 @@ az keyvault secret show --vault-name $KEY_VAULT_NAME --name $KEY_VAULT_SECRET_NA
| `ENTITLEMENT_MEMBER_NAME_INVALID` | ex. `InvalidTestAdmin` | Used for negative testing | no | -- |
| `ENTITLEMENT_MEMBER_NAME_VALID` | `********` | Secret from `$INTEGRATION_TESTER` for userInfo cosmoscollection partitionId | yes | Create in userInfo cosmosCollection |
| `ENTITLEMENT_GROUP_NAME_VALID` | ex. `data.test1` | A group name generated by running integration tests. | no | -- |
| `AZURE_AD_USER_EMAIL` | ex. `********` | Valid member user email in the AD Tenant for Testing | yes | -- |
| `AZURE_AD_USER_OID` | ex. `********` | Valid member user objectIdin the AD Tenant for Testing | yes | -- |
| `AZURE_AD_GUEST_EMAIL` | ex. `********` | Valid guest user email in the AD Tenant for Testing | yes | -- |
| `AZURE_AD_GUEST_OID` | ex. `********` | Valid guest user objectId in the AD Tenant for Testing | yes | -- |
| `AZURE_AD_OTHER_APP_RESOURCE_ID` | ex. `********` | Valid secondary application for Testing | yes | -- |
| `AZURE_AD_OTHER_APP_RESOURCE_OID` | ex. `********` | Valid secondary application for Testing | yes | -- |
| `AZURE_INVALID_EMAIL` | ex. `invalid.test@email.com` | Invalid Email for Testing | no | -- |
| `AZURE_INVALID_APP_ID` | ex. `03015fad-093c-424a-a7c4-42ed9993f9e3` | Invalid Appilication Identity for Testing | no | -- |
| `AZURE_INVALID_ID` | ex. `03012fadBADX424a-a7c4-42ed9993f9e3` | Invalid Identity for Testing | no | -- |
### Configure Maven
......@@ -127,7 +137,140 @@ Jet Brains - the authors of Intellij IDEA, have written an [excellent guide](htt
## Configuring User Entitlements
As of now, the management APIs that enable user entitlements to be configured are a WIP. Until they are complete, here is how you can configure user entitlements manually.
Here is how you can configure user entitlements via the Azure specific API.
###Create a new user or service principal.
The request body contains the user or service principal to create in JSON format. At a minimum, you must specify the required properties for the user or service principal.
The required properties for a user or service principal is the uid and one tenant with one group. The uid is either a user email or a service principal UUID.
You can optionally specify any additional tenants and groups.
####Permissions
The following permission is required to call this API.
service.entitlements.admin
##### POST /profile
| header | value | required |
| --- | --- | --- |
| Authorization | Bearer {token} | Yes |
| Content-Type | application/json | Yes |
| Request body | In the request body, supply a JSON representation of user object. | Yes |
The following table lists the properties that are required when you create a user. .
| Property | Type | Description | Required |
| --- | --- | --- | --- |
| uid | user email or service principal UUID. | The user email or service principal UUID. | Yes |
| id | OID | The OID for the user or service principal. | No value required. |
| tenants| list of TenantInfo | The tenants for the user or service principal. | Yes. |
##### Response
If successful, this method returns 201 response code and user object in the response body.
##### Example: Create a user
##### Request
Here is an example of the request.
###### POST /profile
###### Content-type: application/json
```json
{
"id": "",
"uid": "erik.leckner@wipro.com",
"tenants": [
{
"name": "$SOME_OSDU_TENANT",
"groups": [
"service.storage.admin",
"service.legal.admin",
"data.datalake.admin",
"data.datalake.viewer",
"data.default.viewer"
]
},
{
"name": "$ANOTHER_OSDU_TENANT",
"groups": [
"service.storage.admin"
]
}
]
}
```
In the request body, supply a JSON representation of user object.
###Update a user or service principal.
The request body contains the user or service principal to update in JSON format. At a minimum, you must specify the required properties for the user or service principal.
The required properties for a user or service principal is the uid and one tenant with one group. The uid is either a user email or a service principal UUID.
You can optionally specify any additional tenants and groups.
####Permissions
The following permission is required to call this API.
service.entitlements.admin
##### PUT /profile
| header | value | required |
| --- | --- | --- |
| Authorization | Bearer {token} | Yes |
| Content-Type | application/json | Yes |
| Request body | In the request body, supply a JSON representation of user object. | Yes |
The following table lists the properties that are required when you create a user. .
| Property | Type | Description | Required |
| --- | --- | --- | --- |
| uid | user email or service principal UUID. | The user email or service principal UUID. | Yes |
| id | OID | The OID for the user or service principal. | No value required. |
| tenants| list of TenantInfo | The tenants for the user or service principal. | Yes. |
##### Response
If successful, this method returns 200 response code and user object in the response body.
##### Example: Update a user
##### Request
Here is an example of the request.
###### PUT /profile
###### Content-type: application/json
```json
{
"id": "",
"uid": "erik.leckner@wipro.com",
"tenants": [
{
"name": "$SOME_OSDU_TENANT",
"groups": [
"service.storage.admin",
"service.legal.admin",
"data.datalake.admin",
"data.datalake.viewer"
]
},
{
"name": "$ANOTHER_OSDU_TENANT",
"groups": [
"service.storage.admin"
]
}
]
}
```
In the request body, supply a JSON representation of user object.
## Configuring User Entitlements (Deprecated)
Here is how you can configure user entitlements manually.
- Identify the correct CosmosDB account. This can be found in the output of the infrastructure template. Alternatively, you should be able to identify it as the singular CosmosDB account that is provisioned in the resource group that hosts the this service
- Use the `Data Explorer` tool in the CosmosDB UI and navigate to the `UserInfo` container
......@@ -136,7 +279,8 @@ As of now, the management APIs that enable user entitlements to be configured ar
- If the user does not exist, you can add a document that has the following schema. The exact groups you wish to provision to the user will most likely be different, so be sure to add/remove the appropriate roles. The below listing represents a user with full access to all services.
```json
{
"id": "$IDENTITY_ID",
"id": "$OBJECT_ID",
"uid": "$IDENTITY_ID",
"tenants": [
{
"name": "$SOME_OSDU_TENANT",
......@@ -221,6 +365,15 @@ export DOMAIN="${AZURE_COMPANY_DOMAIN}"
export MY_TENANT="${AZURE_OSDU_TENANT}"
export ENTITLEMENT_GROUP_NAME_VALID="${AZURE_VALID_GROUPNAME}"
export ENTITLEMENT_MEMBER_NAME_INVALID="${AZURE_INVALID_GROUPNAME}"
export AZURE_AD_USER_EMAIL="${AZURE_AD_USER_EMAIL}"
export AZURE_AD_USER_OID="${AZURE_AD_USER_OID}"
export AZURE_AD_GUEST_EMAIL="${AZURE_AD_GUEST_EMAIL}"
export AZURE_AD_GUEST_OID="${AZURE_AD_GUEST_OID}"
export AZURE_AD_OTHER_APP_RESOURCE_ID="${AZURE_AD_OTHER_APP_RESOURCE_ID}"
export AZURE_AD_OTHER_APP_RESOURCE_OID="${AZURE_AD_OTHER_APP_RESOURCE_OID}"
export AZURE_INVALID_EMAIL="invalid.test@email.com"
export AZURE_INVALID_APP_ID="03015fad-093c-424a-a7c4-42ed9993f9e3"
export AZURE_INVALID_ID="03012fadBADX424a-a7c4-42ed9993f9e3"
```
__Azure Service Deployment__
......
// Copyright © Microsoft Corporation
//
// 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 org.opengroup.osdu.azure.entitlements.acceptanceTests;
import com.google.gson.Gson;
import com.sun.jersey.api.client.ClientResponse;
import org.apache.http.HttpStatus;
import org.junit.Test;
import org.opengroup.osdu.azure.entitlements.utils.TestUtils;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class EntitlementsApiGetGroupMembersTests {
/*Forbidden test cases*/
@Test
public void givenAnonymous_whenCallGetGroupMembers_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String path = "groups/" + groupEmail + "/members";
ClientResponse response = TestUtils.send(path, "GET",
TestUtils.getHeaders(TestUtils.getTenantName(), null), "", "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenExpiredJwt_whenCallGetGroupMembers_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String path = "groups/" + groupEmail + "/members";
ClientResponse response = TestUtils.send(path, "GET",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getExpiredToken()), "", "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenJwtNotForThisApp_whenCallGetGroupMembers_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String path = "groups/" + groupEmail + "/members";
ClientResponse response = TestUtils.send(path, "GET",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getTokenForDifferentApp()), "", "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenValidIntegrationTester_whenCallGetGroupMembers_thenOk() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String path = "groups/" + groupEmail + "/members";
ClientResponse response = TestUtils.send(path, "GET",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getToken()), "", "");
assertEquals(HttpStatus.SC_OK, response.getStatus());
String[] responseBody = new Gson().fromJson(response.getEntity(String.class), String[].class);
assertTrue(Arrays.stream(responseBody).anyMatch(member -> member.equals(TestUtils.getValidMember())));
}
}
// Copyright © Microsoft Corporation
//
// 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 org.opengroup.osdu.azure.entitlements.acceptanceTests;
import com.google.gson.Gson;
import com.sun.jersey.api.client.ClientResponse;
import org.apache.http.HttpStatus;
import org.junit.Test;
import org.opengroup.osdu.azure.entitlements.utils.TestUtils;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class EntitlementsApiRemoveGroupMemberTests {
/*Forbidden test cases*/
@Test
public void givenAnonymous_whenCallRemoveGroupMember_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String memberEmail = TestUtils.getValidMember();
String path = "groups/" + groupEmail + "/members/" + memberEmail;
ClientResponse response = TestUtils.send(path, "DELETE",
TestUtils.getHeaders(TestUtils.getTenantName(), null), null, "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenExpiredJwt_whenCallRemoveGroupMember_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String memberEmail = TestUtils.getValidMember();
String path = "groups/" + groupEmail + "/members/" + memberEmail;
ClientResponse response = TestUtils.send(path, "DELETE",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getExpiredToken()), null, "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenJwtNotForThisApp_whenCallRemoveGroupMember_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String memberEmail = TestUtils.getValidMember();
String path = "groups/" + groupEmail + "/members/" + memberEmail;
ClientResponse response = TestUtils.send(path, "DELETE",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getTokenForDifferentApp()), null, "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
@Test
public void givenInvalidMemberEmail_whenCallRemoveGroupMember_thenForbidden() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
String memberEmail = TestUtils.getInvalidMember();
String path = "groups/" + groupEmail + "/members/" + memberEmail;
ClientResponse response = TestUtils.send(path, "DELETE",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getToken()), null, "");
assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
}
/*OK test cases*/
// The Integration Tester is expected to exist before you can run any OpenDES integration tests
// If you change this assumption, or remove any one of the following basic roles, update this test
// and most likely integration tests for other services that require this user
//
// Also integration test can't interactively sign in a real user, yet Entitlements service checks
// the JWT for the user it's supposed to return the groups for. So even if you insert a new user for
// this test, you still can't sign in as that user. Use existing Service Principal here instead.
@Test
public void givenValidIntegrationTester_whenCallRemoveGroupMember_thenOk() throws Exception {
String groupEmail = TestUtils.getValidGroupEmail();
//String memberEmail = TestUtils.getValidMember();
//String path = "groups/" + groupEmail + "/members/" + memberEmail;
//ClientResponse response2 = TestUtils.send(path, "DELETE",
// TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getToken()), null, "");
String postedBody = TestUtils.constructPostBody(TestUtils.getValidMember());
String path = "groups/" + groupEmail + "/members";
ClientResponse response = TestUtils.send(path, "POST",
TestUtils.getHeaders(TestUtils.getTenantName(), TestUtils.getToken()), postedBody, "");
assertEquals(HttpStatus.SC_OK, response.getStatus());
String[] responseBody = new Gson().fromJson(response.getEntity(String.class), String[].class);
assertTrue(Arrays.stream(responseBody).anyMatch(member -> member.equals(TestUtils.getValidMember())));
}
}
......@@ -23,6 +23,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class UserInfoDoc {
private String id;
private String uid;
private UserTenantItem[] tenants;
}
// Copyright © Microsoft
//
// 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 org.opengroup.osdu.azure.entitlements.utils;
public class Config {
private static final String DEFAULT_AZURE_INVALID_EMAIL = "invalid.test@email.com";
private static final String DEFAULT_AZURE_INVALID_APP_ID = "03015fad-093c-424a-a7c4-42ed9993f9e3";
private static final String DEFAULT_AZURE_INVALID_ID = "03012fadBADX424a-a7c4-42ed9993f9e3";
public static String getInvalidEmail() {
return getEnvironmentVariableOrDefaultValue("AZURE_INVALID_EMAIL", DEFAULT_AZURE_INVALID_EMAIL);
}
public static String getInvalidAppId() {
return getEnvironmentVariableOrDefaultValue("AZURE_INVALID_APP_ID", DEFAULT_AZURE_INVALID_APP_ID);
}
public static String getInvalidId() {
return getEnvironmentVariableOrDefaultValue("AZURE_INVALID_ID", DEFAULT_AZURE_INVALID_ID);
}
private static String getEnvironmentVariableOrDefaultValue(String key, String defaultValue) {
String environmentVariable = getEnvironmentVariable(key);
if (environmentVariable == null) {
environmentVariable = defaultValue;
}
return environmentVariable;
}
private static String getEnvironmentVariable(String propertyKey) {
return System.getProperty(propertyKey, System.getenv(propertyKey));
}
}
......@@ -58,7 +58,7 @@ public class TestDataUtils {
}
public static UserInfoDoc createUserInfo(String id, UserTenantItem[] tenants){
return new UserInfoDoc(id, tenants);
return new UserInfoDoc(id, "", tenants);
}
public static String toJson(UserInfoDoc userInfoDoc) {
......@@ -67,5 +67,3 @@ public class TestDataUtils {
return gson.toJson(userInfoDoc);
}
}
......@@ -18,6 +18,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.opengroup.osdu.azure.entitlements.model.UserInfoDoc;
import org.opengroup.osdu.azure.entitlements.model.UserTenantItem;
import java.util.Random;
......@@ -34,14 +35,20 @@ public class TestUserInfoData {
}
public static String getJsonFromTestFile(String test) {
return getJsonFromTestFile(test, generateId());
try {
String json = FileHandler.readFile(getFileName(test));
UserInfoDoc userInfoDoc = fromJson(json);
return toJson(userInfoDoc);
} catch (Exception ex) {
throw new AssertionError(ex.getMessage());
}
}
public static String getJsonFromTestFile(String test, String id) {
try {
String json = FileHandler.readFile(getFileName(test));
UserInfoDoc userInfoDoc = fromJson(json);
userInfoDoc.setId(id);
userInfoDoc.setUid(id);
return toJson(userInfoDoc);
} catch (Exception ex) {
throw new AssertionError(ex.getMessage());
......@@ -53,6 +60,11 @@ public class TestUserInfoData {
return gson.toJson(userInfoDoc);
}
public static String toJson(UserTenantItem[] tenantItems) {
Gson gson = gsonBuilder.serializeNulls().create();
return gson.toJson(tenantItems);
}
public static UserInfoDoc fromJson(String json) {
try {
return gson.fromJson(json, UserInfoDoc.class);
......@@ -69,9 +81,5 @@ public class TestUserInfoData {
}
}
public static String generateId() {
int i = new Random().nextInt(100000);
return "13012fad-test-" + i + "-a7c4-42ed9993f9e5";
}
}
}
\ No newline at end of file
......@@ -45,6 +45,15 @@ public class TestUtils {
private static final String member_name_valid = System.getProperty("ENTITLEMENT_MEMBER_NAME_VALID", System.getenv("ENTITLEMENT_MEMBER_NAME_VALID"));
private static final String member_name_invalid = System.getProperty("ENTITLEMENT_MEMBER_NAME_INVALID", System.getenv("ENTITLEMENT_MEMBER_NAME_INVALID"));
private static final String group_name_valid = System.getProperty("ENTITLEMENT_GROUP_NAME_VALID", System.getenv("ENTITLEMENT_GROUP_NAME_VALID"));
private static final String test_regular_user_id = System.getProperty("AZURE_AD_USER_EMAIL", System.getenv("AZURE_AD_USER_EMAIL"));
private static final String test_regular_user_oid = System.getProperty("AZURE_AD_USER_OID", System.getenv("AZURE_AD_USER_OID"));
private static final String test_guest_user_id = System.getProperty("AZURE_AD_GUEST_EMAIL", System.getenv("AZURE_AD_GUEST_EMAIL"));
private static final String test_guest_user_oid = System.getProperty("AZURE_AD_GUEST_OID", System.getenv("AZURE_AD_GUEST_OID"));
private static final String test_sp_id = System.getProperty("AZURE_AD_OTHER_APP_RESOURCE_ID", System.getenv("AZURE_AD_OTHER_APP_RESOURCE_ID"));
private static final String test_sp_oid = System.getProperty("AZURE_AD_OTHER_APP_RESOURCE_OID", System.getenv("AZURE_AD_OTHER_APP_RESOURCE_OID"));
private static final String test_invalid_user_id = Config.getInvalidEmail();
private static final String test_invalid_app_id = Config.getInvalidAppId();
private static final String test_invalid_id = Config.getInvalidId();
private static String token;
......@@ -55,6 +64,15 @@ public class TestUtils {
public static final String getValidMember() { return member_name_valid; }
public static final String getInvalidMember() { return member_name_invalid; }
public static final String getValidGroupEmail() { return group_name_valid + "@" + tenantName + "." + domain; }
public static final String getTestRegularUserId() { return test_regular_user_id; }
public static final String getTestRegularUserOid() { return test_regular_user_oid; }
public static final String getTestGuestUserId() { return test_guest_user_id; }
public static final String getTestGuestUserOid() { return test_guest_user_oid; }
public static final String getTestInvalidUserId() { return test_invalid_user_id; }
public static final String getTestInvalidAppId() { return test_invalid_app_id; }
public static final String getTestInvalidId() { return test_invalid_id; }
public static final String getTestSpId() { return test_sp_id; }
public static final String getTestSpOid() { return test_sp_oid; }
public static String getToken() throws Exception {
if (token == null || token.isEmpty()) {
......@@ -90,7 +108,15 @@ public class TestUtils {
Client client = TestUtils.getClient();
String mergedURL = new URL(baseUrl + path + query).toString();
System.out.println(String.format("calling API:%s", mergedURL));
System.out.println(String.format("calling %s API:%s", httpMethod, mergedURL));
System.out.println(String.format("request body:%s", requestBody));
System.out.println(String.format("query:%s", query));
if (requestBody != null)
headers.put("Content-Length", Long.toString(requestBody.length()));
else
headers.put("Content-Length", "0");
WebResource webResource = client.resource(mergedURL);
WebResource.Builder builder = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
......
{
"id": "",
"uid": "",
"tenants": [
{
"name": "common",
"groups": [
"service.storage.admin",
"service.legal.admin"
]
},
{
"name": "opendes",
"groups": [
"data.default.owners",
"service.entitlements.admin"
]
}
]
}
{
"id": "",
"uid": "",
"tenants": [
{
"name": "opendes",
"groups": [
"service.storage.admin",
"service.legal.admin",
"data.datalake.viewer",
"service.entitlements.admin"
]