-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add accts linking agama project #7556
Signed-off-by: jgomer2001 <bonustrack310@gmail.com>
- Loading branch information
1 parent
9be78e4
commit 6185bed
Showing
12 changed files
with
1,211 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
65 changes: 65 additions & 0 deletions
65
jans-casa/plugins/acct-linking/extras/agama/code/io.jans.casa.acctlinking.Launcher.flow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
Flow io.jans.casa.acctlinking.Launcher | ||
Basepath "" | ||
Configs providers | ||
Inputs providerId uidRef | ||
|
||
provider = providers.$providerId | ||
//See class io.jans.inbound.Provider for reference | ||
|
||
When provider is null or provider.enabled is false | ||
msg = Call java.lang.String#format "Provider '%s' not recognized. Is it enabled?" providerId | ||
obj = { success: false, error: msg } | ||
Finish obj | ||
|
||
//Launch matching flow and retrieve profile | ||
Log "Initiating external authentication for identity provider '%'" providerId | ||
obj = Trigger $provider.flowQname provider | ||
|
||
When obj.success is false | ||
Finish obj | ||
|
||
field = Call io.jans.inbound.Utils#getMappingField provider.mappingClassField | ||
idProc = Call io.jans.inbound.IdentityProcessor#new provider | ||
profile = Call idProc applyMapping obj.data field | ||
|
||
field = null | ||
//In profile, every key is associated to a list | ||
Log "@d Mapped profile is\n" profile | ||
|
||
When profile.ID is null or profile.ID.empty is true | ||
obj = { success: false, error: "Mapped profile misses value for 'ID'" } | ||
Finish obj | ||
|
||
When profile.mail is null or profile.mail.empty is true | ||
Log "Incoming user has no e-mail value" | ||
|
||
//Prompt for e-mail if necessary | ||
When provider.requestForEmail is true | ||
obj = RRF "email-prompt.ftlh" | ||
mail = obj.email | ||
|
||
When mail is null | ||
obj = { success: false, error: "Unable to complete profile data: e-mail not provided" } | ||
Finish obj | ||
|
||
profile.mail = [ mail ] | ||
|
||
jansExtUid = Call io.jans.casa.acctlinking.UidUtils#computeExtUid providerId profile.ID[0] | ||
uid = null | ||
|
||
When profile.uid is not null | ||
uid = profile.uid[0] | ||
|
||
uid = Call io.jans.casa.acctlinking.UidUtils#lookupUid uidRef uid profile.ID[0] "jansExtUid" jansExtUid | ||
profile.jansExtUid = Call io.jans.casa.acctlinking.UidUtils#attrValuesAdding uid "jansExtUid" jansExtUid | ||
|
||
profile.uid = [ uid ] | ||
profile.ID = null //ID not part of DB schema - jansExtUid has what is needed | ||
|
||
uid | E = Call idProc process profile | ||
When E is null | ||
Finish uid | ||
|
||
Log "@e Unable to process the incoming user" E | ||
obj = { success: false, error: E.message } | ||
Finish obj |
71 changes: 71 additions & 0 deletions
71
jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/Mappings.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.jans.casa.acctlinking; | ||
|
||
import java.util.function.UnaryOperator; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Fields of this class can be referenced in the config properties of flow | ||
* io.jans.casa.acctlinking.Launcher | ||
*/ | ||
public final class Mappings { | ||
|
||
public static final UnaryOperator<Map<String, Object>> GOOGLE = | ||
|
||
profile -> { | ||
Map<String, Object> map = new HashMap<>(); | ||
|
||
map.put("ID", profile.get("sub")); | ||
map.put("mail", profile.get("email")); | ||
map.put("cn", profile.get("name")); | ||
map.put("sn", profile.get("family_name")); | ||
map.put("displayName", profile.get("given_name")); | ||
map.put("givenName", profile.get("given_name")); | ||
|
||
return map; | ||
}; | ||
|
||
//See https://developers.facebook.com/docs/graph-api/reference/user | ||
public static final UnaryOperator<Map<String, Object>> FACEBOOK = | ||
|
||
profile -> { | ||
Map<String, Object> map = new HashMap<>(); | ||
|
||
map.put("ID", profile.get("id")); | ||
map.put("mail", profile.get("email")); | ||
map.put("cn", profile.get("name")); | ||
map.put("sn", profile.get("last_name")); | ||
map.put("displayName", profile.get("first_name")); | ||
map.put("givenName", profile.get("first_name")); | ||
|
||
return map; | ||
}; | ||
|
||
public static final UnaryOperator<Map<String, Object>> APPLE = | ||
|
||
profile -> { | ||
Map<String, Object> map = new HashMap<>(); | ||
|
||
map.put("ID", profile.get("sub")); | ||
map.put("mail", profile.get("email")); | ||
|
||
return map; | ||
}; | ||
|
||
//See https://docs.github.com/en/rest/users/users | ||
public static final UnaryOperator<Map<String, Object>> GITHUB = | ||
|
||
profile -> { | ||
Map<String, Object> map = new HashMap<>(); | ||
|
||
map.put("ID", profile.getOrDefault("login", profile.get("id"))); | ||
map.put("mail", profile.get("email")); | ||
map.put("displayName", profile.get("name")); | ||
map.put("givenName", profile.get("name")); | ||
|
||
return map; | ||
}; | ||
|
||
private Mappings() { } | ||
|
||
} |
83 changes: 83 additions & 0 deletions
83
jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/UidUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package io.jans.casa.acctlinking; | ||
|
||
import io.jans.as.common.model.common.User; | ||
import io.jans.as.common.service.common.UserService; | ||
import io.jans.service.cache.CacheProvider; | ||
import io.jans.service.cdi.util.CdiUtil; | ||
|
||
import java.io.IOException; | ||
import java.util.*; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class UidUtils { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(Utils.class); | ||
|
||
public static String lookupUid(String uidRef, String uid, String extUid, String jansExtAttrName, | ||
String jansExtUid) throws IOException { | ||
|
||
if (uidRef == null) { | ||
boolean uidPassed = uid != null; | ||
|
||
if (uidPassed) { | ||
logger.debug("Using uid passed: {}", uid); | ||
return uid; | ||
} | ||
|
||
//Find if the external account is already linked to a local one | ||
User user = CdiUtil.bean(UserService.class).getUserByAttribute(jansExtAttrName, jansExtUid, true); | ||
if (user == null) { | ||
logger.info("Building a uid based on external id {}", extUid); | ||
return extUid + "-" + randSuffix(3); | ||
} | ||
logger.info("Using uid of the account already linked to {}", extUid); | ||
return user.getUserId(); | ||
} | ||
|
||
logger.debug("Looking up uid ref {}", uidRef); | ||
Object value = CdiUtil.bean(CacheProvider.class).get(uidRef); | ||
if (value == null) throw new IOException("uid reference passed not found in Cache!"); | ||
|
||
return value.toString(); | ||
|
||
} | ||
|
||
public static List<String> attrValuesAdding(String uid, String attributeName, String valueToAdd) { | ||
|
||
User user = CdiUtil.bean(UserService.class).getUserByAttribute("uid", uid, false); | ||
if (user == null) return Collections.singletonList(valueToAdd); | ||
|
||
List<String> values = new ArrayList<>(); | ||
List<String> currentValues = Optional.ofNullable(user.getAttributeValues(attributeName)) | ||
.orElse(Collections.emptyList()); | ||
values.addAll(currentValues); | ||
|
||
if (!currentValues.contains(valueToAdd)) { | ||
values.add(valueToAdd); | ||
} | ||
return values; | ||
|
||
} | ||
|
||
public static String computeExtUid(String providerId, String id) { | ||
return providerId + ":" + id; | ||
} | ||
|
||
private Utils() { } | ||
|
||
// The idea here is to generate a random 3-char lengthed string "easy to remember" | ||
private static String randSuffix(int randSuffixLen) { | ||
|
||
String s = ""; | ||
int radix = Math.min(15, Character.MAX_RADIX); //radix 15 entails characters: 0-9 plus a-e | ||
|
||
for (int i = 0; i < randSuffixLen; i++) { | ||
long rnd = Math.random() * radix; // rnd will belong to [0, radix - 1] | ||
s += Integer.toString((int) rnd, radix); // this adds a single character to s | ||
} | ||
return s; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"projectName": "casa-account-linking", | ||
"author": "jgomer2001", | ||
"type": "Community", | ||
"version": "1.0.0", | ||
"description": "A helper project for Jans Casa accounts linking plugin", | ||
"noDirectLaunch": [ ], | ||
"configs": { | ||
"io.jans.casa.acctlinking.Launcher": { | ||
|
||
"facebook": { | ||
"flowQname": "io.jans.inbound.GenericProvider", | ||
"displayName": "Facebook", | ||
"mappingClassField": "io.jans.casa.acctlinking.Mappings.FACEBOOK", | ||
"logoImg": "facebook.png", | ||
"oauthParams": { | ||
"authzEndpoint": "https://www.facebook.com/v14.0/dialog/oauth", | ||
"tokenEndpoint": "https://graph.facebook.com/v14.0/oauth/access_token", | ||
"userInfoEndpoint": "https://graph.facebook.com/v14.0/me", | ||
"clientId": "<APP-ID>", | ||
"clientSecret": "<APP-SECRET>", | ||
"scopes": ["email", "public_profile"] | ||
} | ||
}, | ||
|
||
"github": { | ||
"flowQname": "io.jans.inbound.GenericProvider", | ||
"displayName": "Github", | ||
"mappingClassField": "io.jans.casa.acctlinking.Mappings.GITHUB", | ||
"oauthParams": { | ||
"authzEndpoint": "https://github.com/login/oauth/authorize", | ||
"tokenEndpoint": "https://github.com/login/oauth/access_token", | ||
"userInfoEndpoint": "https://api.github.com/user", | ||
"clientId": "<APP-ID>", | ||
"clientSecret": "<APP-SECRET>", | ||
"scopes": ["user"] | ||
} | ||
}, | ||
|
||
"google": { | ||
"flowQname": "io.jans.inbound.GenericProvider", | ||
"displayName": "Google", | ||
"mappingClassField": "io.jans.casa.acctlinking.Mappings.GOOGLE", | ||
"enabled": false, | ||
"skipProfileUpdate": true, | ||
"oauthParams": { | ||
"authzEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", | ||
"tokenEndpoint": "https://oauth2.googleapis.com/token", | ||
"userInfoEndpoint": "https://www.googleapis.com/oauth2/v3/userinfo", | ||
"clientId": "<APP-ID>", | ||
"clientSecret": "<APP-SECRET>", | ||
"scopes": ["email", "profile"] | ||
} | ||
} | ||
|
||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions
50
jans-casa/plugins/acct-linking/extras/agama/web/email-prompt.ftlh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<!doctype html> | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="icon" href="${webCtx.contextPath}/servlet/favicon" type="image/x-icon"> | ||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" | ||
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> | ||
<style> | ||
#logo { | ||
max-height: 3.25rem; | ||
margin: 0.5rem; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
|
||
<div class="d-flex flex-column align-items-center justify-content-between min-vh-100 w-100"> | ||
<header class="d-flex w-100 justify-content-between border-bottom"> | ||
<img id="logo" src="https://gluu.org/wp-content/uploads/2021/02/janssen-project-transparent-630px-182px-300x86.png" /> | ||
</header> | ||
|
||
<div class="row col-sm-10 col-md-5 mb-5 pb-3"> | ||
|
||
<div class="border border-1 rounded mb-3 p-5"> | ||
<p class="fs-5 mb-5">Please provide an e-mail address to proceed</p> | ||
|
||
<form method="post" enctype="application/x-www-form-urlencoded"> | ||
<div class="mb-4 row"> | ||
<label for="email" class="col-md-3 col-form-label">Your e-mail</label> | ||
<div class="col-md-9"> | ||
<input type="email" class="form-control" name="email" id="email" autofocus required> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col-md-12 d-flex justify-content-end"> | ||
<input type="submit" class="btn btn-success px-4" value="Continue"> | ||
</div> | ||
</div> | ||
</form> | ||
</div> | ||
|
||
</div> | ||
|
||
<footer class="d-flex flex-column align-items-center w-100 pb-2"> | ||
<hr class="w-75"> | ||
</footer> | ||
</div> | ||
|
||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.