Skip to content

Commit

Permalink
shared secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
culmat committed Apr 25, 2024
1 parent d9ce11b commit 9408fc9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 22 deletions.
46 changes: 29 additions & 17 deletions src/main/java/com/baloise/azure/FunctionalOrgEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;

import com.azure.identity.ClientSecretCredential;
Expand All @@ -34,15 +36,12 @@
* Azure Functions with HTTP Trigger.
*/
public class FunctionalOrgEndpoint {
/**
* This function listens at endpoint "/api/Hello". Two ways to invoke it using
* "curl" command in bash: 1. curl -d "HTTP Body" {your host}/api/Hello 2. curl
* "{your host}/api/Hello?name=HTTP%20Query"
*/

Vault lazyVault = null;
Graph lazygraph = null;
ObjectMapper objectMapper = new ObjectMapper();
private Set<String> lazyValidTokens;
final static String TOKEN_KEY = "TOKENS";

Vault vault() {
if(lazyVault == null) {
Expand All @@ -51,7 +50,7 @@ Vault vault() {
return lazyVault;
}

Graph graph() {
Graph graph(boolean obfuscated) {
if(lazygraph == null) {
final String[] scopes = new String[] { AzureProperties.defaultScope() };
final ClientSecretCredential credential =
Expand All @@ -64,9 +63,9 @@ Graph graph() {
.build();


lazygraph = new Graph(credential, scopes);
lazygraph = new Graph(credential, scopes, obfuscated);
}
return lazygraph;
return lazygraph.withObfuscation(obfuscated);
}

@FunctionName("V1")
Expand All @@ -83,26 +82,39 @@ public HttpResponseMessage v1(
try {
List<String> path = asList(request.getUri().getPath().split("/"));
path = path.subList(path.indexOf("V1")+1, path.size());
boolean obfuscated = !hasValidToken(request);
if(path.size() ==1 && "~roleSchemes".equals(path.get(0))) {
return createJSONResponse(request, Map.of("default", graph().getDefaultRoleScheme(), "roleSchemes", graph().getRoleSchemes()));
return createJSONResponse(request, Map.of("default", graph(obfuscated).getDefaultRoleScheme(), "roleSchemes", graph(obfuscated).getRoleSchemes()));
} else if(path.size() ==2 && "~avatar".equals(path.get(0))) {
return createAvatarResponse(request, path.get(1));
return createAvatarResponse(request, path.get(1), obfuscated);
}


if(request.getQueryParameters().containsKey("clear")) graph().clear();
final StringTree child = graph().getOrg().getChild(path.toArray(new String[0]));
if(request.getQueryParameters().containsKey("clear")) graph(obfuscated).clear();
final StringTree child = graph(obfuscated).getOrg().getChild(path.toArray(new String[0]));

return child.isLeaf() ? createTeamResponse(request, context, child) : createOrganisationResponse(request, context, child);
return child.isLeaf() ? createTeamResponse(request, context, child, obfuscated) : createOrganisationResponse(request, context, child);

} catch (Throwable t) {
context.getLogger().log(Level.WARNING, t.getLocalizedMessage(), t);
return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body(t.getLocalizedMessage()).build();
}
}

private HttpResponseMessage createAvatarResponse(HttpRequestMessage<Optional<String>> request, String id) throws IOException {
byte[] avatar = graph().avatar(id);
private boolean hasValidToken(HttpRequestMessage<Optional<String>> request) {
String token = request.getQueryParameters().get("token");
return token != null ? validTokens().contains(token) : false;
}

private Set<String> validTokens() {
if(lazyValidTokens == null) {
lazyValidTokens = Collections.singleton(vault().getSecret(TOKEN_KEY, true));
}
return lazyValidTokens;
}

private HttpResponseMessage createAvatarResponse(HttpRequestMessage<Optional<String>> request, String id, boolean obfuscated) throws IOException {
byte[] avatar = graph(obfuscated).avatar(id);
String myETag = String.valueOf(Arrays.hashCode(avatar));
String theirETag = ignoreKeyCase(request.getHeaders()).get("If-None-Match");
boolean sameEtag = Objects.equals(myETag, theirETag);
Expand Down Expand Up @@ -130,10 +142,10 @@ public String get(Object key) {
return lowMap;
}

private HttpResponseMessage createTeamResponse(HttpRequestMessage<Optional<String>> request, ExecutionContext context, StringTree team)
private HttpResponseMessage createTeamResponse(HttpRequestMessage<Optional<String>> request, ExecutionContext context, StringTree team, boolean obfuscated)
throws JsonProcessingException {

final Map<String, Object> body = graph().loadTeam(team.getProperty("id"), getRoles(request));
final Map<String, Object> body = graph(obfuscated).loadTeam(team.getProperty("id"), getRoles(request));
body.put("name", team.getName());
body.put("url", format("%s/%s", getPath(request),team.getName()));
return createJSONResponse(request, body);
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/com/baloise/azure/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.azure.identity.ClientSecretCredential;
import com.microsoft.graph.models.Team;
Expand All @@ -43,12 +42,14 @@ public class Graph {
final Pattern orgPattern = Pattern.compile(orgMarker+"\\s*\\(\\s*([\\w"+orgSeparator+"]+)\\s*\\)");
StringTree org = new StringTree("root");
GraphServiceClient graphClient;
private boolean obfuscated = false;

Graph() {
// for testing only
}

public Graph(ClientSecretCredential credential, String[] scopes) {
public Graph(ClientSecretCredential credential, String[] scopes, boolean obfuscated) {
this.obfuscated = obfuscated;
graphClient = new GraphServiceClient(credential, scopes);
}

Expand All @@ -58,7 +59,7 @@ public void clear() {
}

public byte[] avatar(String id) throws IOException {
id = "unknown_person.jpg";
if(obfuscated) id = "unknown_person.jpg";
try(InputStream is = graphClient.users().byUserId(id).photo().content().get()){
return is.readAllBytes();
} catch (Exception e) {
Expand Down Expand Up @@ -87,7 +88,7 @@ public StringTree getOrg() {

private String notNull(String mayBeNull) {
String ret = mayBeNull == null? "" :mayBeNull;
return (ret + "...").substring(0, 3)+"...";
return obfuscated ? (ret + "...").substring(0, 3)+"..." : ret;
}

private List<String> notNull(List<String> strings) {
Expand All @@ -109,7 +110,7 @@ public Map<String, Object> loadTeam(String teamId, String ... roleNames) {
mappedMember.put("preferredLanguage",notNull(member.getPreferredLanguage()));
mappedMember.put("businessPhones",notNull(member.getBusinessPhones()));
mappedMember.put("department",notNull(member.getDepartment()));
//mappedMember.put("userKey",notNull(member.getMailNickname()));
if(!obfuscated) mappedMember.put("userKey",notNull(member.getMailNickname()));
mappedMember.put("usageLocation",notNull(member.getUsageLocation()));
((Set<String>) mappedMember.computeIfAbsent("roles",(ignored)-> new TreeSet<>())).add(roleName);
});
Expand Down Expand Up @@ -178,5 +179,10 @@ StringTree parseOrg(String description) {
public Map<String, Set<String>> getRoleSchemes() {
return rolesSchemes.entrySet().stream().filter(e->e.getValue().size()>1).collect(toMap(Entry::getKey,Entry::getValue));
}

public Graph withObfuscation(boolean obfuscated) {
this.obfuscated = obfuscated;
return this;
}

}

0 comments on commit 9408fc9

Please sign in to comment.