Skip to content

Commit fb7d473

Browse files
committed
WIP for #360
1 parent d8f80ac commit fb7d473

File tree

8 files changed

+90
-10
lines changed

8 files changed

+90
-10
lines changed

client/src/api/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ export function allowedAttributes() {
265265
return fetchJson("/api/v1/manage/allowed-attributes", {}, {}, false);
266266
}
267267

268+
export function autoCompleteEntities(query, entityType) {
269+
return fetchJson(`/api/v1/manage/autocomplete/${entityType}?query=${encodeURIComponent(query)}`);
270+
}
271+
268272
//Connections
269273
export function newConnection(connection) {
270274
return postPutJson("/api/v1/connections", connection, "POST");

client/src/locale/en.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ const en = {
115115
system: "System",
116116
users: "Users",
117117
organizations: "Organizations",
118-
organizationPendingApproval: "Pending approval"
118+
organizationPendingApproval: "Pending approval",
119+
manage: "Manage"
119120
},
120121
welcome: {
121122
greeting: "Welcome {{name}}",
@@ -186,7 +187,8 @@ const en = {
186187
joins: "Join Requests",
187188
invitations: "Invitations",
188189
access: "Access",
189-
information: "App information"
190+
information: "App information",
191+
manage: "Manage"
190192
},
191193
joinRequest: {
192194
info: "You do not have access to <strong>{{name}}</strong>'s environment. You can request access from the administrator.",
@@ -1165,6 +1167,14 @@ const en = {
11651167
stepExplanation:"→ Users may access the application, but must log in with a higher LoA or MFA"
11661168
},
11671169
negateApplication: "Select <strong>Negate selection</strong> to apply this policy to all service providers except the ones you chose.",
1170+
},
1171+
manage: {
1172+
name: "Name",
1173+
organization: "Organization",
1174+
type: "Entity type",
1175+
oidc10_rp: "OIDC Relying Party",
1176+
saml20_sp: "SAML Service Provider",
1177+
searchPlaceHolder: "Search for Manage entities"
11681178
}
11691179

11701180
}

client/src/pages/ApplicationDetail.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ const ApplicationDetail = ({anonymous, refreshUser}) => {
9292
setShowNewPolicyChoice(true);
9393
return;
9494
} else {
95-
newCurrentPolicy = policyType === policyTypes.step ? policyTemplateStepUp(user.identityProvider.data.entityid) :
96-
policyTemplateRegular(user.identityProvider.data.entityid);
95+
newCurrentPolicy = policyType === policyTypes.step ?
96+
policyTemplateStepUp(user.identityProvider.data.entityid, serviceProvider.data.entityid) :
97+
policyTemplateRegular(user.identityProvider.data.entityid, serviceProvider.data.entityid);
9798
}
9899
} else {
99100
newCurrentPolicy = allPolicies.find(policy => policy.id === policyIdentifier);

client/src/pages/System.jsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ import {Organizations} from "./Organizations.jsx";
88
import {useAppStore} from "../stores/AppStore.js";
99
import {mainMenuItems} from "../utils/MenuItems.js";
1010
import {useShallow} from "zustand/react/shallow";
11+
import {Manage} from "./Manage.jsx";
1112

12-
const tabNames = ["users", "organizations", "organizationPendingApproval"]
13+
const tabNames = ["users", "organizations", "organizationPendingApproval", "manage"]
14+
15+
const organizationTabs = ["organizations", "organizationPendingApproval"];
1316

1417
const System = () => {
1518
const {tab = "users"} = useParams();
@@ -37,11 +40,14 @@ const System = () => {
3740
activeMenuItem: null
3841
});
3942

40-
const tabChanged = (name) => {
43+
const tabChanged = name => {
44+
const refreshRequired = name !== currentTab && organizationTabs.includes(name) &&
45+
organizationTabs.includes(currentTab);
46+
debugger;
4147
setCurrentTab(name);
4248
const path = encodeURIComponent(`/system/${name}`);
4349
//We need to force a refresh of the Organization component that is used twice
44-
navigate(`/refresh-route/${path}`);
50+
navigate(refreshRequired ? `/refresh-route/${path}` : path);
4551
}
4652

4753
const renderCurrentTab = () => {
@@ -55,6 +61,9 @@ const System = () => {
5561
case "organizationPendingApproval": {
5662
return <Organizations pendingApproval={true}/>
5763
}
64+
case "manage": {
65+
return <Manage />
66+
}
5867
}
5968
}
6069

server/src/main/java/access/api/ManageController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.net.URI;
2525
import java.net.URL;
2626
import java.nio.charset.Charset;
27+
import java.util.ArrayList;
2728
import java.util.List;
2829
import java.util.Map;
2930

@@ -183,6 +184,16 @@ public ResponseEntity<List<Map<String, Object>>> uniquePolicyName(@RequestBody M
183184
List<Map<String, Object>> policies = manage.uniquePolicyName(properties);
184185
return ResponseEntity.ok(policies);
185186
}
187+
@GetMapping("/autocomplete/{type}")
188+
public List<Map<String, Object>> autoCompleteEntities(@PathVariable EntityType type,
189+
@RequestParam("query") String query) {
190+
Map<String, List<Map<String, Object>>> entities = manage.autoCompleteEntities(type, query);
191+
//We concat the suggestions and alternatives
192+
List<Map<String, Object>> alternatives = entities.getOrDefault("alternatives", new ArrayList<>());
193+
List<Map<String, Object>> suggestions = entities.getOrDefault("suggestions", new ArrayList<>());
194+
alternatives.addAll(suggestions);
195+
return alternatives;
196+
}
186197

187198

188199
@GetMapping("/allowed-attributes")

server/src/main/java/access/manage/LocalManage.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package access.manage;
22

33
import access.exception.NotFoundException;
4-
import access.model.*;
4+
import access.model.Connection;
5+
import access.model.EntityType;
6+
import access.model.Environment;
7+
import access.model.Organization;
8+
import access.model.User;
59
import com.fasterxml.jackson.core.type.TypeReference;
610
import com.fasterxml.jackson.databind.ObjectMapper;
711
import lombok.SneakyThrows;
@@ -12,7 +16,12 @@
1216
import org.springframework.core.io.Resource;
1317
import org.springframework.util.StringUtils;
1418

15-
import java.util.*;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.UUID;
1625
import java.util.stream.Collectors;
1726
import java.util.stream.IntStream;
1827
import java.util.stream.Stream;
@@ -272,7 +281,7 @@ public List<Map<String, Object>> policiesByIdentityProvider(String identityProvi
272281
List<Map<String, String>> identityProviderIds = (List<Map<String, String>>)
273282
data.getOrDefault("identityProviderIds", List.of());
274283
return identityProviderIds.stream()
275-
.anyMatch(m -> m.get("name").equals(identityProviderEntityId));
284+
.anyMatch(m -> m.get("name").equals(identityProviderEntityId));
276285
})
277286
.toList();
278287
}
@@ -315,4 +324,24 @@ public void deletePolicy(Map<String, Object> policy) {
315324
public void connectWithoutInteraction(Map<String, Object> identityProvider, Map<String, Object> serviceProvider, User currentUser) {
316325
//nope
317326
}
327+
328+
@Override
329+
public Map<String, List<Map<String, Object>>> autoCompleteEntities(EntityType type, String query) {
330+
String lowerCaseQuery = query.toLowerCase();
331+
return Map.of("suggestions", this.allProviders.get(type).stream()
332+
.filter(entity -> {
333+
Map<String, Object> data = getData(entity);
334+
String entityid = (String) data.get("entityid");
335+
if (entityid.toLowerCase().contains(lowerCaseQuery)) {
336+
return true;
337+
}
338+
Map<String, Object> metaDataFields = getMetaDataFields(data);
339+
return Stream.of("name:en", "name:nl", "OrganizationName:en", "OrganizationName:nl")
340+
.anyMatch(attr -> {
341+
String val = (String) metaDataFields.get("attr");
342+
return StringUtils.hasText(val) && val.toLowerCase().contains(query);
343+
});
344+
})
345+
.toList());
346+
}
318347
}

server/src/main/java/access/manage/Manage.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package access.manage;
22

33
import access.model.*;
4+
import org.springframework.web.bind.annotation.PathVariable;
5+
import org.springframework.web.bind.annotation.RequestParam;
46

57
import java.util.*;
68

@@ -57,6 +59,8 @@ List<Map<String, Object>> policiesByServiceProvider(String identityProviderEntit
5759

5860
List<Map<String, Object>> uniquePolicyName(Map<String, Object> properties);
5961

62+
Map<String, List<Map<String, Object>>> autoCompleteEntities(EntityType type, String query);
63+
6064
List<Map<String, Object>> allowedAttributes();
6165

6266
void deletePolicy(Map<String, Object> policy);

server/src/main/java/access/manage/RemoteManage.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.io.IOException;
2727
import java.lang.reflect.Type;
2828
import java.net.URI;
29+
import java.net.URLEncoder;
30+
import java.nio.charset.Charset;
2931
import java.util.HashMap;
3032
import java.util.List;
3133
import java.util.Map;
@@ -421,6 +423,16 @@ public void deletePolicy(Map<String, Object> policy) {
421423
restTemplate.delete(url);
422424
}
423425

426+
@Override
427+
public Map<String, List<Map<String, Object>>> autoCompleteEntities(EntityType type, String query) {
428+
RestTemplate restTemplate = environmentRestTemplate(Environment.PROD);
429+
String url = String.format("%s/manage/api/internal/autocomplete/%s?query=%s",
430+
environmentUrl(Environment.PROD),
431+
type.name(),
432+
URLEncoder.encode(query, Charset.defaultCharset()));
433+
return restTemplate.getForObject(url, Map.class);
434+
}
435+
424436
@Override
425437
public void connectWithoutInteraction(Map<String, Object> identityProvider, Map<String, Object> serviceProvider, User user) {
426438
RestTemplate restTemplate = environmentRestTemplate(Environment.PROD);

0 commit comments

Comments
 (0)