Skip to content

Commit

Permalink
feat(agama): add utility classes for inbound identity (#2204)
Browse files Browse the repository at this point in the history
* feat: add classes for inbound identity #2197

* docs: update docs #2197

* chore: make sonar happier #2197

* chore: make sonar really happier #2197
  • Loading branch information
jgomer2001 committed Aug 23, 2022
1 parent 5357f1c commit 29f58ee
Show file tree
Hide file tree
Showing 19 changed files with 728 additions and 15 deletions.
29 changes: 29 additions & 0 deletions agama/inboundID/CustomMappings.java.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.jans.inbound;

import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;

/**
* Fields of this class can be referenced in the config properties of flow ExternalSiteLogin
* (see the flow docs). If you are placing this file in the 'scripts' directory of Agama to avoid
* server restarts, insert an instruction like <code>Call io.jans.inbound.CustomMappings#class</code>
* at the beginning of the flow's code for changes in this class to take effect immediately. When
* you are done, comment/remove the instruction and optionally put the final version of this class
* in a jar file under 'custom/libs' directory
*/
public final class CustomMappings {

public static final UnaryOperator<Map<String, Object>> SAMPLE_MAPPING =

profile -> {
Map<String, Object> map = new HashMap<>();
//Fill your map as desired with data from input profile. See examples in io.jans.inbound.Mappings
//value = profile.get("...")
//map.put(Attrs.UID, ... );
return map;
};

private CustomMappings() { }

}
96 changes: 96 additions & 0 deletions agama/inboundID/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<artifactId>agama-inbound</artifactId>
<packaging>jar</packaging>
<!--name>Supporting classes for inbound identity using Agama flows</name-->

<parent>
<groupId>io.jans</groupId>
<artifactId>agama</artifactId>
<version>1.0.2-SNAPSHOT</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<repositories>
<repository>
<id>jans</id>
<name>Jans repository</name>
<url>https://maven.jans.io/maven</url>
</repository>
</repositories>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>

<!-- SERVLET -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>

<!-- JAX-RS -->
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.jans</groupId>
<artifactId>jans-core-util</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.jans</groupId>
<artifactId>jans-core-service</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>oauth2-oidc-sdk</artifactId>
<version>9.41</version>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<!-- already in jans-auth war -->
<scope>provided</scope>
</dependency>
</dependencies>

</project>
17 changes: 17 additions & 0 deletions agama/inboundID/src/main/java/io/jans/inbound/Attrs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.jans.inbound;

/**
* This class provides constants for the most commonly used attribute names in Janssen Server database
*/
public final class Attrs {

private Attrs() { }

public static final String UID = "uid";
public static final String MAIL = "mail";
public static final String CN = "cn";
public static final String DISPLAY_NAME = "displayName";
public static final String GIVEN_NAME = "givenName";
public static final String SN = "sn";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.jans.inbound;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.UnaryOperator;

public class IdentityProcessor {

private Provider provider;
private UnaryOperator<Map<String, Object>> mapping;

public IdentityProcessor(Provider provider, ClassLoader classLoader)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

this.provider = provider;
this.mapping = getMapping(provider.getMappingClassField(),
classLoader == null ? getClass().getClassLoader() : classLoader);

}

public Map<String, List<Object>> applyMapping(Map<String, Object> profile) {

Map<String, Object> pr = mapping.apply(profile);
Map<String, List<Object>> res = new HashMap<>();

for (String key: pr.keySet()) {
Object value = pr.get(key);

if (key != null && value != null) {
List<Object> newValue;

if (value.getClass().isArray()) {
newValue = Arrays.asList(value);
} else if (Collection.class.isInstance(value)) {
newValue = new ArrayList<>((Collection) value);
} else {
newValue = Collections.singletonList(value);
}
res.put(key, newValue);
}
}
return res;

}

public String process(Map<String, List<?>> profile) {//throws Exception {
//Provisions the user and returns its local id (inum)
//reject if there are null values
if (profile.isEmpty() && provider == null) return null;
return "";
}

private UnaryOperator<Map<String, Object>> getMapping(String field, ClassLoader clsLoader)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

int i = 0;
boolean valid = field != null;

if (valid) {
i = field.lastIndexOf(".");
valid = i > 0 && i < field.length() - 1;
}
if (!valid) throw new IllegalAccessException("Unexpected value passed for mapping field: " + field);

String clsName = field.substring(0, i);
Class<?> cls = clsLoader.loadClass(clsName);
Field f = cls.getDeclaredField(field.substring(i + 1));
return (UnaryOperator<Map<String, Object>>) f.get(cls);

}

}
56 changes: 56 additions & 0 deletions agama/inboundID/src/main/java/io/jans/inbound/Mappings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.jans.inbound;

import java.util.function.UnaryOperator;
import java.util.Map;

/**
* Fields of this class can be referenced in the config properties of flow ExternalSiteLogin
* (see the flow docs).
*/
public final class Mappings {

public static final UnaryOperator<Map<String, Object>>

GOOGLE = profile -> Map.of(
Attrs.UID, "google-" + profile.get("sub"),
Attrs.MAIL, profile.get("email"),
Attrs.CN, profile.get("name"),
Attrs.SN, profile.get("family_name"),
Attrs.DISPLAY_NAME, profile.get("given_name"),
Attrs.GIVEN_NAME, profile.get("given_name")
);

public static final UnaryOperator<Map<String, Object>>
//See https://developers.facebook.com/docs/graph-api/reference/user

FACEBOOK = profile -> Map.of(
Attrs.UID, "facebook-" + profile.get("id"),
Attrs.MAIL, profile.get("email"),
Attrs.CN, profile.get("name"),
Attrs.SN, profile.get("last_name"),
Attrs.DISPLAY_NAME, profile.get("first_name"),
Attrs.GIVEN_NAME, profile.get("first_name")
);

public static final UnaryOperator<Map<String, Object>>

APPLE = profile -> Map.of(
Attrs.UID, "apple-" + profile.get("sub"),
Attrs.MAIL, profile.get("email"),
Attrs.DISPLAY_NAME, profile.get("name"),
Attrs.GIVEN_NAME, profile.get("name")
);

public static final UnaryOperator<Map<String, Object>>
//See https://docs.github.com/en/rest/users/users

GITHUB = profile -> Map.of(
Attrs.UID, "github-" + profile.getOrDefault("login", profile.get("id")),
Attrs.MAIL, profile.get("email"),
Attrs.DISPLAY_NAME, profile.get("name"),
Attrs.GIVEN_NAME, profile.get("name")
);

private Mappings() { }

}
79 changes: 79 additions & 0 deletions agama/inboundID/src/main/java/io/jans/inbound/Provider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.jans.inbound;

public class Provider {

private String flowQname;
private String displayName;
private String logoImg;
private String mappingClassField;

private boolean enabled = true;
private boolean skipProfileUpdate;
private boolean requestForEmail;
private boolean emailLinkingSafe;

public String getFlowQname() {
return flowQname;
}

public void setFlowQname(String flowQname) {
this.flowQname = flowQname;
}

public String getDisplayName() {
return displayName;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}

public String getMappingClassField() {
return mappingClassField;
}

public void setMappingClassField(String mappingClassField) {
this.mappingClassField = mappingClassField;
}

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public boolean isSkipProfileUpdate() {
return skipProfileUpdate;
}

public void setSkipProfileUpdate(boolean skipProfileUpdate) {
this.skipProfileUpdate = skipProfileUpdate;
}

public String getLogoImg() {
return logoImg;
}

public void setLogoImg(String logoImg) {
this.logoImg = logoImg;
}

public boolean isRequestForEmail() {
return requestForEmail;
}

public void setRequestForEmail(boolean requestForEmail) {
this.requestForEmail = requestForEmail;
}

public boolean isEmailLinkingSafe() {
return emailLinkingSafe;
}

public void setEmailLinkingSafe(boolean emailLinkingSafe) {
this.emailLinkingSafe = emailLinkingSafe;
}

}
Loading

0 comments on commit 29f58ee

Please sign in to comment.