/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2012-2016 ForgeRock AS.
*/
/**
* A simple {@code Map} based collection resource provider.
*/
// TODO: filters, sorting, paged results.
/**
* Creates a backend
*/
public IdentityResourceV2(String userType, MailServerLoader mailServerLoader, IdentityServicesImpl identityServices,
CoreWrapper coreWrapper, RestSecurityProvider restSecurityProvider, ConsoleConfigHandler configHandler,
}
/**
* Enum to lazy init the CTSPersistentStore variable in a thread safe manner.
*/
private enum CTSHolder {
private CTSHolder() {
}
}
}
// Constructor used for testing...
this.objectType = userType;
this.mailServerLoader = mailServerLoader;
this.configHandler = configHandler;
this.identityResourceV1 = new IdentityResourceV1(userType, mailServerLoader, identityServices, coreWrapper,
this.identityServices = identityServices;
}
return identityServices;
}
/*
* package private for access by UserIdentityResourceV3
*/
}
/**
* Gets the user id from the session provided in the server context
*
* @param context Current Server Context
*/
try {
// build resource
if (debug.messageEnabled()) {
debug.message("IdentityResource.idFromSession() :: Retrieved ID for user={}", amIdentity.getName());
}
} catch (SSOException e) {
} catch (IdRepoException ex) {
}
}
}
return realm;
}
return sessionRealm;
}
/**
* Generates a secure hash to use as token ID
* @param resource string that will be used to create random hash
* @return random string
*/
return null;
}
}
/**
* Generates a CTS REST Token, including realm information in its {@code CoreTokenField.STRING_ONE} field.
*
* @param resource The resource for which the tokenID will be generated
* @param userId The user's ID, associated with the token
* @param tokenLifeTimeSeconds Length of time from now in second for the token to remain valid
* @param realmName The name of the realm in which this token is valid
* @return the generated CTS REST token
*/
}
return ctsToken;
}
/**
* This method will create a confirmation email that contains a {@link org.forgerock.openam.cts.api.tokens.Token},
* confirmationId and email that was provided in the request.
* @param context Current Server Context
* @param request Request from client to retrieve id
*/
private Promise<ActionResponse, ResourceException> createRegistrationEmail(final Context context, final ActionRequest request, final String realm,
final RestSecurity restSecurity) {
try {
if (restSecurity == null) {
if (debug.warningEnabled()) {
"restSecurity={}", restSecurity);
}
throw new NotFoundException("Rest Security Service not created" );
}
if (!restSecurity.isSelfServiceRestEndpointEnabled()) {
if (debug.warningEnabled()) {
}
throw new NotSupportedException("Legacy Self Service REST Endpoint is not enabled.");
}
if (!restSecurity.isSelfRegistration()) {
if (debug.warningEnabled()) {
}
throw new NotSupportedException("Self Registration is not enabled.");
}
// Get full deployment URL
// Get the email address provided from registration page
throw new BadRequestException("Email not provided");
}
// Retrieve email registration token life time
// Create CTS Token
// Store token in datastore
// Create confirmationId
String confirmationId = Hash.hash(tokenID + emailAddress + SystemProperties.get(AM_ENCRYPTION_PWD));
// Build Confirmation URL
} else {
}
confirmationLink = confURLBuilder.append("?confirmationId=").append(requestParamEncode(confirmationId))
.toString();
// Send Registration
if (debug.messageEnabled()) {
debug.message("IdentityResource.createRegistrationEmail() :: Sent notification to={} with subject={}. "
}
} catch (BadRequestException be) {
debug.warning("IdentityResource.createRegistrationEmail: Cannot send email to {}", emailAddress, be);
} catch (NotFoundException nfe) {
debug.warning("IdentityResource.createRegistrationEmail: Cannot send email to {}", emailAddress, nfe);
} catch (NotSupportedException nse) {
if (debug.warningEnabled()) {
emailAddress, nse);
}
} catch (Exception e) {
}
}
/**
* Sends email notification to end user
* @param to Resource receiving notification
* @param subject Notification subject
* @param message Notification Message
* @param confirmationLink Confirmation Link to be sent
* @throws Exception when message cannot be sent
*/
try {
} catch (SMSException smse) {
if (debug.errorEnabled()) {
}
throw new InternalServerErrorException("Cannot create the service: " + MailServerImpl.SERVICE_NAME, smse);
} catch (SSOException ssoe) {
if (debug.errorEnabled()) {
}
throw new InternalServerErrorException("Cannot create the service: " + MailServerImpl.SERVICE_NAME, ssoe);
}
if (debug.errorEnabled()) {
}
}
// Get MailServer Implementation class
try {
} catch (IllegalStateException e) {
}
try {
// Check if subject has not been included
// Use default email service subject
}
} catch (Exception e) {
if (debug.warningEnabled()) {
}
subject = "";
}
try {
// Check if Custom Message has been included
// Use default email service message
}
} catch (Exception e) {
if (debug.warningEnabled()) {
}
}
// Send the emails via the implementation class
try {
} catch (MessagingException e) {
if (debug.errorEnabled()) {
}
throw new InternalServerErrorException("Failed to send mail", e);
}
}
/**
* Validates the current goto against the list of allowed gotos, and returns either the allowed
* goto as sent in, or the server's default goto value.
*
* @param context Current Server Context
* @param request Request from client to confirm registration
*/
/* package private for access by UserIdentityResourceV3
*/
final ActionRequest request) {
try {
} catch (SSOException ssoe){
if (debug.errorEnabled()) {
}
}
}
/**
* Will validate confirmationId is correct
* @param request Request from client to confirm registration
*/
//email or username value used to create confirmationId
try{
if (debug.errorEnabled()) {
}
throw new BadRequestException("confirmationId not provided");
}
}
}
if (debug.errorEnabled()) {
}
throw new BadRequestException("Required information not provided");
}
if (debug.errorEnabled()) {
}
throw new BadRequestException("tokenId not provided");
}
// build resource
if (debug.messageEnabled()) {
debug.message("{} :: Confirmed for token '{}' with confirmation '{}'", METHOD, tokenID, confirmationId);
}
} catch (BadRequestException bre) {
debug.warning("{} :: Cannot confirm registration/forgotPassword for : {}", METHOD, hashComponent, bre);
} catch (ResourceException re) {
} catch (CoreTokenException cte) {
}
}
/**
* Validates a provided token against a selection of criteria to ensure that it's valid for the given
* realm. This function is the validation equiv. of
* {@link IdentityResourceV2#generateToken(String, String, Long, String)}.
*
* @param tokenID The token ID to retrieve from the store, against which to perform validation
* @param realm The realm under which the current request is being made, must match the realm the token was
* generated by, not null
* @param hashComponent The hash component used to created the confirmationId
* @param confirmationId The confirmationId, not null
* @throws NotFoundException If the token doesn't exist in the store
* @throws CoreTokenException If there were unexpected issues communicating with the CTS
* @throws BadRequestException If the realm or confirmationId were invalid for the token retrieved
*/
private void validateToken(String tokenID, String realm, String hashComponent, String confirmationId)
throws ResourceException, CoreTokenException {
//check expiry
if (ctsToken == null || TimeUtils.toUnixTime(ctsToken.getExpiryTimestamp()) < TimeUtils.currentUnixTime()) {
throw ResourceException.getException(HttpURLConnection.HTTP_GONE, "Cannot find tokenID: " + tokenID);
}
// check confirmationId
}
//check realm
}
if (debug.messageEnabled()) {
}
}
/**
* {@inheritDoc}
*/
public Promise<ActionResponse, ResourceException> actionCollection(Context context, ActionRequest request) {
return idFromSession(context);
} else { // for now this is the only case coming in, so fail if otherwise
return RestUtils.generateUnsupportedOperation();
}
}
/**
* Generates the e-mail contents based on the incoming request.
*
* Will only send the e-mail if all the following conditions are true:
*
* - Forgotten Password service is enabled
* - User exists
* - User has an e-mail address in their profile
* - E-mail service is correctly configured.
*
* @param context Non null.
* @param request Non null.
* @param realm Used as part of user lookup.
* @param restSecurity Non null.
*/
try {
// Check to make sure forgotPassword enabled
if (restSecurity == null) {
if (debug.warningEnabled()) {
}
}
if (!restSecurity.isSelfServiceRestEndpointEnabled()) {
if (debug.warningEnabled()) {
}
}
if (!restSecurity.isForgotPassword()) {
if (debug.warningEnabled()) {
}
}
// Generate Admin Token
List<String> searchResults = identityServices.search(new CrestQuery("*"), searchAttributes, adminToken);
if (searchResults.isEmpty()) {
throw new NotFoundException("User not found");
throw new ConflictException("Multiple users found");
} else {
for (Map.Entry<String, Set<String>> attribute : asMap(identityDetails.getAttributes()).entrySet()) {
}
}
}
}
if (!isUserActive(uid)) {
throw new ForbiddenException("Request is forbidden for this user");
}
// Check if email is provided
throw new BadRequestException("No email provided in profile.");
}
// Get full deployment URL
// Retrieve email registration token life time
if (restSecurity == null) {
if (debug.warningEnabled()) {
}
throw new NotFoundException("Rest Security Service not created");
}
// Generate Token
// Store token in datastore
// Create confirmationId
// Build Confirmation URL
} else {
}
.toString();
// Send Registration
if (debug.messageEnabled()) {
}
}
} catch (ResourceException re) {
} catch (Exception e) {
// Intentional - all other errors are considered Internal Error.
}
}
private Map<String, Set<String>> getAttributeFromRequest(JsonValue jsonBody) throws BadRequestException {
throw new BadRequestException("Both username and email specified - only one allowed in request.");
}
}
}
throw new BadRequestException("Username or email not provided in request");
}
/**
* Perform an anonymous update of a user's password using the provided token.
*
* The token must match a token placed in the CTS in order for the request
* to proceed.
*
* @param context Non null
* @param request Non null
* @param realm Non null
*/
try{
throw new BadRequestException("username not provided");
}
throw new BadRequestException("new password not provided");
}
// update Identity
// Update instance with new password value
// Only remove the token if the update was successful, errors will be set in the handler.
try {
// Even though the generated token will eventually timeout, delete it after a successful read
// so that the reset password request cannot be made again using the same token.
} catch (DeleteFailedException e) {
// Catch this rather than letting it stop the process as it is possible that between successfully
// reading and deleting, the token has expired.
if (debug.messageEnabled()) {
"read failed due to " + e.getMessage(), e);
}
}
return newResultPromise(response);
}
});
} catch (ResourceException re) {
}
}
/**
* Updates an instance given a JSON object with User Attributes
* @param admin Token that has administrative privileges
* @param details Json Value containing details of user identity
* @return A successful promise if the update was successful
*/
private Promise<ActionResponse, ResourceException> updateInstance(SSOToken admin, final JsonValue details, final String realm) {
try {
throw new BadRequestException("Illegal arguments: One or more required arguments is null or empty");
}
// update resource with new details
realm, resourceId);
// read updated identity back to client
admin);
// handle updated resource
} catch (final Exception e) {
debug.error("IdentityResource.updateInstance() :: Cannot UPDATE in realm={} for resourceId={}", realm,
resourceId, e);
}
}
try{
if (!restSecurity.isSelfRegistration()) {
throw new BadRequestException("Self-registration disabled");
}
throw new BadRequestException("Email not provided");
}
// Convert to IDRepo Attribute schema
throw new BadRequestException("confirmationId not provided");
}
throw new BadRequestException("tokenId not provided");
}
// create an Identity
// Only remove the token if the create was successful, errors will be set in the handler.
try {
// Even though the generated token will eventually timeout, delete it after a successful read
// so that the completed registration request cannot be made again using the same token.
} catch (DeleteFailedException e) {
// Catch this rather than letting it stop the process as it is possible that between successfully
// reading and deleting, the token has expired.
if (debug.messageEnabled()) {
" after a successful read failed due to " + e.getMessage(), e);
}
}
return newResultPromise(response);
}
});
} catch (BadRequestException bre) {
} catch (ResourceException re) {
} catch (ServiceNotFoundException snfe) {
// Failure from RestSecurity
}
}
/**
* {@inheritDoc}
*/
try {
}
}
if (debug.messageEnabled()) {
}
} catch (ResourceException re) {
}
} else {
}
}
/**
* Creates an a resource using a privileged token
* @param admin Token that has administrative privileges
* @param details resource details that needs to be created
* @return A successful promise containing the identity details if the create was successful
*/
private Promise<ActionResponse, ResourceException> createInstance(SSOToken admin, JsonValue details, final String realm) {
} else {
}
}
});
}
/**
* {@inheritDoc}
*/
final CreateRequest request) {
try {
// anyone can create an account add
// check to see if request has included resource ID
if (resourceId != null) {
}
}
} else {
}
UserAttributeInfo userAttributeInfo = configHandler.getConfig(realm, UserAttributeInfoBuilder.class);
return newResultPromise(resource);
} else {
}
}
});
} catch (SSOException e) {
return new ForbiddenException(e).asPromise();
} catch (BadRequestException bre) {
}
}
private Promise<IdentityDetails, ResourceException> attemptResourceCreation(String realm, SSOToken admin,
try {
// Create the resource
// Read created resource
if (debug.messageEnabled()) {
debug.message("IdentityResource.createInstance() :: Created resourceId={} in realm={} by AdminID={}",
}
} catch (final ObjectNotFound notFound) {
debug.error("IdentityResource.createInstance() :: Cannot READ resourceId={} : Resource cannot be found.",
} catch (final TokenExpired tokenExpired) {
debug.error("IdentityResource.createInstance() :: Cannot CREATE resourceId={} : Unauthorized", resourceId,
} catch (final NeedMoreCredentials needMoreCredentials) {
debug.error("IdentityResource.createInstance() :: Cannot CREATE resourceId={} : Token is not authorized",
} catch (final GeneralAccessDeniedError accessDenied) {
return new ForbiddenException().asPromise();
} catch (GeneralFailure generalFailure) {
return new BadRequestException("Resource cannot be created: "
} catch (AccessDenied accessDenied) {
return new ForbiddenException("Token is not authorized: " + accessDenied.getMessage(), accessDenied)
.asPromise();
} catch (ResourceException re) {
} catch (final Exception e) {
}
return newResultPromise(dtls);
}
/**
* {@inheritDoc}
*/
public Promise<ResourceResponse, ResourceException> deleteInstance(final Context context, final String resourceId, final DeleteRequest request) {
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
}
/**
* {@inheritDoc}
*/
}
private boolean checkValidPassword(String username, char[] password, String realm) throws BadRequestException {
throw new BadRequestException("Invalid Username or Password");
}
try {
if (debug.messageEnabled()) {
}
return false;
}
}
/**
* {@inheritDoc}
*/
try {
// Retrieve details about user to be updated
// Continue modifying the identity if read success
// If the user wants to modify his password, he should use a different action.
if (isUpdatingHisOwnPassword) {
return new BadRequestException("Cannot update user password via PUT. "
+ "Use POST with _action=changePassword or _action=forgotPassword.").asPromise();
}
}
}
throw new BadRequestException("Illegal arguments: One or more required arguments is null or empty");
}
throw new BadRequestException("id in path does not match id in request body");
}
UserAttributeInfo userAttributeInfo = configHandler.getConfig(realm, UserAttributeInfoBuilder.class);
// Handle attribute change when password is required
// Get restSecurity for this realm
// Make sure user is not admin and check to see if we are requiring a password to change any attributes
boolean hasReauthenticated = false;
// If attribute is not available set newAttr variable to empty string for use in comparison
// Get the value of current attribute
}
}
// Compare newAttr and currentAttr
// check header to make sure that password is there then check to see if it's correct
//set a boolean value so we know reauth has been done
hasReauthenticated = true;
//continue will allow attribute(s) change(s)
} else {
throw new BadRequestException("Must provide a valid confirmation password to change " +
newAttr + "'");
}
}
}
}
}
// update resource with new details
// read updated identity back to client
return newResultPromise(this.identityResourceV1.buildResourceResponse(resourceId, context, checkIdent));
} catch (final ObjectNotFound onf) {
debug.error("IdentityResource.updateInstance() :: Cannot UPDATE resourceId={} : Could not find the " +
.asPromise();
} catch (final NeedMoreCredentials needMoreCredentials) {
debug.error("IdentityResource.updateInstance() :: Cannot UPDATE resourceId={} : Token is not authorized",
} catch (final TokenExpired tokenExpired) {
} catch (final AccessDenied accessDenied) {
} catch (final GeneralFailure generalFailure) {
debug.error("IdentityResource.updateInstance() :: Cannot UPDATE resourceId={}", resourceId, generalFailure);
} catch (BadRequestException bre){
} catch (NotFoundException e) {
debug.warning("IdentityResource.updateInstance() :: Cannot UPDATE resourceId={} : Could not find the " +
"resource", resourceId, e);
.asPromise();
} catch (ResourceException re) {
} catch (final Exception e) {
}
}
} else {
return toEncode;
}
}
/**
* @return the object type
*/
return objectType;
}
}