Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-->
# Search For User Authentication Tree Node

A simple authentication node for ForgeRock's Identity Platform 5.5 and above. This node checks if a user exists.
A simple authentication node for ForgeRock's Identity Platform 5.5 and above. This node searches the user data store for a matching identity based on configurable search attributes. Possible outcomes are "found" - a unique match is found, "ambiguous" - multiple potential matches found, or "not found" - no matching identity. See screenshot below for an example.

## Installation

Expand All @@ -28,10 +28,9 @@ Deploy the node and wire the appropriate exhausts.

The code in this repository has binary dependencies that live in the ForgeRock maven repository. Maven can be configured to authenticate to this repository by following the following [ForgeRock Knowledge Base Article](https://backstage.forgerock.com/knowledge/kb/article/a74096897).

Edit the necessary ProfileAttributeDecisionNode.java as appropriate. To rebuild, run "mvn clean install" in the directory containing the pom.xml
Edit the necessary SearchForUserNode.java as appropriate. To rebuild, run "mvn clean install" in the directory containing the pom.xml

![ScreenShot](./search-for-user-1.png)
![ScreenShot](./search-for-user-2.png)

## Disclaimer
The sample code described herein is provided on an "as is" basis, without warranty of any kind, to the fullest extent permitted by law. ForgeRock does not warrant or guarantee the individual success developers may have in implementing the sample code on their development platforms or in production configurations.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<artifactId>search-for-user-node</artifactId>
<groupId>org.forgerock.am</groupId>
<version>6.0.0-SNAPSHOT</version>
<version>6.5.0</version>
<name>Search For User Authentication Node</name>

<description>An Authentication Tree Node for ForgeRock's Identity Platform</description>
Expand Down
Binary file modified search-for-user-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,22 @@
package org.forgerock.openam.auth.nodes;

import com.google.inject.assistedinject.Assisted;
import com.iplanet.sso.SSOException;
import com.sun.identity.shared.debug.Debug;
import org.forgerock.guava.common.collect.ImmutableList;
import com.sun.identity.sm.DNMapper;
import org.forgerock.json.JsonValue;
import org.forgerock.openam.annotations.sm.Attribute;
import org.forgerock.openam.auth.node.api.*;
import javax.inject.Inject;
import static com.sun.identity.idm.IdUtils.getAMIdentityRepository;
import static org.forgerock.openam.auth.node.api.SharedStateConstants.REALM;
import static org.forgerock.openam.auth.node.api.SharedStateConstants.USERNAME;
import org.forgerock.openam.core.CoreWrapper;
import com.sun.identity.idm.*;

import java.util.*;

import org.forgerock.openam.utils.CollectionUtils;
import org.forgerock.util.i18n.PreferredLocales;

import com.sun.identity.idm.IdUtils;


@Node.Metadata(outcomeProvider = SearchForUserNode.OutcomeProvider.class,
configClass = SearchForUserNode.Config.class)
Expand All @@ -56,12 +55,11 @@ public interface Config {
@Attribute(order = 100)
default String sharedStateAttribute() {
return USERNAME;
};
}

//Toggle as to whether UA is stored in the clear or SHA256 hashed for privacy
@Attribute(order = 200)
default String datastoreAttribute() {
return USERNAME;
default List<String> datastoreAttributes() {
return Arrays.asList("username");
}

}
Expand All @@ -79,61 +77,76 @@ public SearchForUserNode(@Assisted Config config, CoreWrapper coreWrapper) throw
this.coreWrapper = coreWrapper;
}


@Override
public Action process(TreeContext context) throws NodeProcessException {

debug.message("[" + DEBUG_FILE + "]: " + "Starting");
AMIdentity userIdentity = null;

//Pull out the user object
if (config.datastoreAttribute() == USERNAME && config.sharedStateAttribute() == USERNAME){
userIdentity = coreWrapper.getIdentity(context.sharedState.get(USERNAME).asString(),context.sharedState.get(REALM).asString());
} else {
Set<String> userSearchAttributes = new HashSet<>();
userSearchAttributes.add(config.datastoreAttribute());
debug.message("[" + DEBUG_FILE + "]: " + "Datastore attribute: {}", config.datastoreAttribute());
debug.message("[" + DEBUG_FILE + "]: " + "Shared state attribute: {}, and value: {}", config.sharedStateAttribute(), context.sharedState.get(config.sharedStateAttribute()).asString());
userIdentity = IdUtils.getIdentity(context.sharedState.get(config.sharedStateAttribute()).asString(), context.sharedState.get(REALM).asString(),userSearchAttributes);
Set<String> userSearchAttributes = new HashSet<String>(config.datastoreAttributes());

}
AMIdentityRepository amIdRepo = getAMIdentityRepository(DNMapper.orgNameToDN(context.sharedState.get(REALM).asString()));
IdSearchControl idsc = new IdSearchControl();
idsc.setRecursive(true);
idsc.setAllReturnAttributes(true);
Set results = Collections.EMPTY_SET;
String searchUsername = context.sharedState.get(config.sharedStateAttribute()).asString();

IdSearchResults searchResults;
try {
idsc.setMaxResults(0);
Map<String, Set<String>> searchAVP = CollectionUtils.toAvPairMap(userSearchAttributes, searchUsername);
idsc.setSearchModifiers(IdSearchOpModifier.OR, searchAVP);
searchResults = amIdRepo.searchIdentities(IdType.USER, "*", idsc);

if (userIdentity == null) {

debug.error("[" + DEBUG_FILE + "]: " + "Unable to find user");
return goTo("notFound").build();

} else {

debug.message("[" + DEBUG_FILE + "]: " + "user found: {}", userIdentity.getName());
//ensure username is set in sharedstate
context.sharedState.put(USERNAME, userIdentity.getName());
return goTo("found").build();
if (searchResults != null) {
results = searchResults.getSearchResults();
}

}
if (results == null || results.size() == 0) {
debug.error("[" + DEBUG_FILE + "]: " + "Unable to find any matching user");
return Action.goTo("notFound").build();
}

if (results.size() != 1) {
debug.error("[" + DEBUG_FILE + "]: " + "More than one matching user profile found - ambiguous");
return Action.goTo("ambiguous").build();
}

} catch (Exception e) {
userIdentity = (AMIdentity)results.iterator().next();
} catch (IdRepoException e) {
debug.warning("Error searching for user identity");
} catch (SSOException e) {
debug.warning("Error searching for user identity");
}

debug.error("[" + DEBUG_FILE + "]: " + "Node exception", e);
return goTo("notFound").build();
}
debug.message("[" + DEBUG_FILE + "]: " + "user found: {}", userIdentity.getName());
//ensure username is set in sharedstate
context.sharedState.put(USERNAME, userIdentity.getName());
return goTo("found").build();
}


private Action.ActionBuilder goTo(String outcome) {
return Action.goTo(outcome);
}


static final class OutcomeProvider implements org.forgerock.openam.auth.node.api.OutcomeProvider {
private static final String BUNDLE = SearchForUserNode.class.getName().replace(".", "/");

@Override
public List<Outcome> getOutcomes(PreferredLocales locales, JsonValue nodeAttributes) {
ResourceBundle bundle = locales.getBundleInPreferredLocale(BUNDLE, OutcomeProvider.class.getClassLoader());
return ImmutableList.of(
new Outcome( "found", bundle.getString("found")),
new Outcome("notFound", bundle.getString("notFound")));
List<Outcome> results = new ArrayList<>();
results.add(new Outcome("found", "Found"));
results.add(new Outcome("notFound", "Not Found"));
results.add(new Outcome("ambiguous", "Ambiguous"));
return Collections.unmodifiableList(results);
}
}
}



Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
#
# Copyright 2017 ForgeRock AS.
#
#simon.moffatt@forgerock.com
#jon.knight@forgerock.com


# Description
nodeDescription=Search For User

# Outcomes
found=User Found
notFound=User Not Found
notFound=User Not Found
ambiguous=Ambigous