IdentityResource.java revision 1889f15ae9583798fd7ce87822d9056ae072e963
/*
* 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-2014 ForgeRock AS
*/
/**
* A simple {@code Map} based collection resource provider.
*/
public final class IdentityResource implements CollectionResourceProvider {
// TODO: filters, sorting, paged results.
private ServiceConfigManager mailmgr;
private ServiceConfig mailscm;
private final MailServerLoader mailServerLoader;
/**
* Creates a backend
*/
}
/**
* Enum to lazy init the CTSPersistentStore variable in a thread safe manner.
*/
private enum CTSHolder {
private final CTSPersistentStore cts;
private CTSHolder() {
}
static CTSPersistentStore getCTS() {
}
}
// Constructor used for testing...
IdentityResource(String userType, ServiceConfigManager mailmgr, ServiceConfig mailscm, MailServerLoader mailServerLoader) {
this.mailServerLoader = mailServerLoader;
}
/**
* Gets the user id from the session provided in the server context
*
* @param context Current Server Context
* @param request Request from client to retrieve id
* @param handler Result handler
*/
try {
// build resource
} catch (SSOException e) {
} catch (IdRepoException ex) {
}
}
/**
* 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;
}
}
}
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
* @param handler Result handler
*/
private void createRegistrationEmail(final ServerContext context, final ActionRequest request, final String realm,
try {
if(restSecurity == null){
"Rest Security not created. restSecurity = " + restSecurity);
throw new NotFoundException("Rest Security Service not created" );
}
if(!restSecurity.isSelfRegistration()){
throw new NotFoundException("Self Registration is not accessible.");
}
// 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 {
}
.toString();
// Send Registration
} catch (BadRequestException be) {
+ be.getMessage());
} catch (NotFoundException nfe){
+ nfe.getMessage());
} catch (Exception e){
+ e.getMessage());
}
}
/**
* 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) {
throw new InternalServerErrorException("Cannot create the service: " + MailServerImpl.SERVICE_NAME, smse);
} catch (SSOException ssoe) {
throw new InternalServerErrorException("Cannot create the service: " + MailServerImpl.SERVICE_NAME, ssoe);
}
}
// Get MailServer Implementation class
try {
} catch (IllegalStateException e) {
throw new InternalServerErrorException(error, e);
}
try {
// Check if subject has not been included
// Use default email service subject
}
} catch (Exception e) {
subject = "";
}
try {
// Check if Custom Message has been included
// Use default email service message
}
} catch (Exception e) {
}
// Send the emails via the implementation class
try {
} catch (MessagingException e) {
throw new InternalServerErrorException(error, e);
}
}
/**
* Will validate confirmationId is correct
* @param context Current Server Context
* @param request Request from client to confirm registration
* @param handler Result handler
*/
try{
throw new BadRequestException("Email not provided");
}
throw new BadRequestException("confirmationId not provided");
}
throw new BadRequestException("tokenId not provided");
}
// Check Token is still in CTS
// Check that tokenID is not expired
}
// check confirmationId
+ confirmationId);
}
// build resource
} catch (BadRequestException be){
+ email);
} catch (Exception e){
+ email + e);
}
}
/**
* {@inheritDoc}
*/
} else { // for now this is the only case coming in, so fail if otherwise
final ResourceException e =
new NotSupportedException("Actions are not supported for resource instances");
handler.handleError(e);
}
}
/**
* Uses an amAdmin SSOtoken to create an AMIdentity from the UID provided and checks
* @param uid the universal identifier of the user
* @return true is the user is active;false otherwise
* @throws NotFoundException invalid SSOToken, invalid UID
*/
try {
return userIdentity.isActive();
} catch (IdRepoException idr) {
} catch (SSOException ssoe){
}
}
private void generateNewPasswordEmail(final ServerContext context, final ActionRequest request, final String realm,
try {
// Check to make sure forgotPassword enabled
if(restSecurity == null){
"Rest Security not created. restSecurity = " + restSecurity);
throw new NotFoundException("Rest Security Service not created" );
}
if(!restSecurity.isForgotPassword()){
+ restSecurity.isForgotPassword());
throw new NotFoundException("Forgot password is not accessible.");
}
// Generate Admin Token
// Get the user id provided from forgot password page
throw new BadRequestException("Username not provided");
}
// Look up Identity
idsvc = new IdentityServicesImpl();
}
}
if(!isUserActive(uid)){
throw new ForbiddenException("Request is forbidden for this user");
}
// Check if email is provided
throw new InternalServerErrorException("No email provided in profile.");
}
// Get full deployment URL
// Retrieve email registration token life time
if(restSecurity == null){
"Rest Security not created. restSecurity = " + restSecurity);
throw new NotFoundException("Rest Security Service not created" );
}
// Generate Token
// Store token in datastore
// Create confirmationId
String confirmationId = Hash.hash(ctsToken.getTokenId() + username + SystemProperties.get("am.encryption.pwd"));
// Build Confirmation URL
} else {
}
.toString();
// Send Registration
} catch (BadRequestException be) {
+ " Exception " + be);
} catch (NotFoundException nfe){
+ " Exception " + nfe);
} catch (ForbiddenException fe){
+ " Exception " + fe);
}catch (CoreTokenException cte){
+ " Exception " + cte);
} catch (InternalServerErrorException ise){
+ " Exception " + ise);
} catch (Exception e){
+ " Exception " + e);
handler.handleError(ResourceException.getException(ResourceException.INTERNAL_ERROR, "Failed to send mail", e));
}
}
private void anonymousUpdate(final ServerContext context, final ActionRequest request, final String realm,
try{
throw new BadRequestException("username not provided");
}
throw new BadRequestException("new password not provided");
}
// Check that tokenID is not expired
}
// check confirmationId
+ confirmationId);
}
// 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()) {
" after a successful read failed due to " + e.getMessage(), e);
}
}
}
} catch (BadRequestException be){
} catch (CoreTokenException cte){
} catch (Exception e){
}
}
/**
* 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
* @param handler handles result of operation
* @return true if the update was successful
*/
boolean successfulUpdate = false;
try {
idsvc = new IdentityServicesImpl();
throw new BadRequestException("Illegal arguments: One or more required arguments is null or empty");
}
// update resource with new details
// read updated identity back to client
// handle updated resource
successfulUpdate = true;
}
return successfulUpdate;
}
private void anonymousCreate(final ServerContext context, final ActionRequest request, final String realm,
try{
throw new BadRequestException("Email not provided");
}
// Convert to IDRepo Attribute schema
throw new BadRequestException("confirmationId not provided");
}
throw new BadRequestException("tokenId not provided");
}
// Check Token is still in CTS
// Check that tokenID is not expired
}
// check confirmationId
+ confirmationId);
}
// 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);
}
}
}
} catch (BadRequestException be){
} catch (NotFoundException nfe){
} catch (Exception e){
}
}
/**
* {@inheritDoc}
*/
public void actionInstance(final ServerContext context, final String resourceId, final ActionRequest request,
final ResourceException e =
new NotSupportedException("Actions are not supported for resource instances");
handler.handleError(e);
}
/**
* Creates an a resource using a privileged token
* @param admin Token that has administrative privileges
* @param details resource details that needs to be created
* @param handler handles result of operation
* @return true if the create was successful
*
*/
boolean successfulCreate = false;
try {
idsvc = new IdentityServicesImpl();
// Create the resource
// Read created resource
successfulCreate = true;
} catch (final ObjectNotFound notFound) {
} catch (final DuplicateObject duplicateObject) {
} catch (final TokenExpired tokenExpired) {
} catch (final NeedMoreCredentials needMoreCredentials) {
}
return successfulCreate;
}
/**
* {@inheritDoc}
*/
// anyone can create an account add
try {
idsvc = new IdentityServicesImpl();
// check to see if request has included resource ID
if(resourceId != null ){
throw new BadRequestException("id in path does not match id in request body");
}
}
} else {
}
// Create the resource
// Read created resource
} catch (final ObjectNotFound notFound) {
} catch (final DuplicateObject duplicateObject) {
} catch (final TokenExpired tokenExpired) {
} catch (final NeedMoreCredentials needMoreCredentials) {
} catch(BadRequestException be) {
be);
}
}
/**
* {@inheritDoc}
*/
public void deleteInstance(final ServerContext context, final String resourceId, final DeleteRequest request,
try {
// read to see if resource is available to user
// delete the resource
} catch (final NeedMoreCredentials ex) {
resourceId + ": User does not have enough privileges.");
} catch (final ObjectNotFound notFound) {
} catch (final TokenExpired tokenExpired) {
} catch (final AccessDenied accessDenied) {
} catch (final GeneralFailure generalFailure) {
exception.getMessage());
}
}
/**
* Returns a JsonValue containing appropriate identity details
*
* @param details The IdentityDetails of a Resource
* @return The JsonValue Object
*/
try {
}
return result;
} catch (final Exception e) {
throw new JsonValueException(result);
}
}
/**
* Returns an IdentityDetails from a JsonValue
*
* @param jVal The JsonValue Object to be converted
* @return The IdentityDetails object
*/
try {
try {
if (childValue.isString()) {
} else if (childValue.isList()) {
}
}
} catch (Exception e) {
"Cannot Traverse JsonValue" + e);
}
} catch (final Exception e) {
" Cannot convert JsonValue to IdentityDetails." + e);
//deal with better exceptions
}
return identity;
}
/**
* {@inheritDoc}
*/
public void patchInstance(final ServerContext context, final String resourceId, final PatchRequest request,
handler.handleError(e);
}
/**
* {@inheritDoc}
*/
final QueryResultHandler handler) {
try {
// This will only return 1 user..
// getQueryFilter() is not implemented yet..returns dummy false value
queryFilter = "*";
}
}
}
}
/**
* {@inheritDoc}
*/
public void readInstance(final ServerContext context, final String resourceId, final ReadRequest request,
try {
idsvc = new IdentityServicesImpl();
} catch (final NeedMoreCredentials needMoreCredentials) {
handler.handleError(new ForbiddenException("User does not have enough privileges.", needMoreCredentials));
} catch (final ObjectNotFound objectNotFound) {
} catch (final TokenExpired tokenExpired) {
} catch (final AccessDenied accessDenied) {
} catch (final GeneralFailure generalFailure) {
}
}
private boolean checkValidPassword(String username, char[] password, String realm) throws BadRequestException {
throw new BadRequestException("Invalid Username or Password");
}
try {
while (lc.hasMoreRequirements()) {
// loop through the requires setting the needs..
if (callbacks[i] instanceof NameCallback) {
} else if (callbacks[i] instanceof PasswordCallback) {
} else {
}
}
// there's missing requirements not filled by this
throw new BadRequestException("Insufficient Requirements");
}
}
// validate the password..
return true;
} else {
return false;
}
} catch (Exception e) {
}
return false;
}
try {
"Cannot retrieve ServerContext as HttpContext");
return null;
}
//get the oldusername from header directly
for (String s : headerList) {
}
}
} catch (Exception e) {
"Cannot get currentpassword from ServerContext!" + e);
}
return null;
}
/**
* {@inheritDoc}
*/
public void updateInstance(final ServerContext context, final String resourceId, final UpdateRequest request,
try {
// Retrieve details about user to be updated
// Continue modifying the identity if read success
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");
}
// Handle userpassword change
// Check that the attribute userpassword is in the json object
// If so password reset attempt
// same password as before, update the attributes
} else {
// check header to make sure that currentpassword is there check to see if it's correct
if(strPass != null && !strPass.isEmpty() && checkValidPassword(resourceId, strPass.toCharArray(), realm)){
//continue will allow password change
} else{
throw new BadRequestException("Invalid Password");
}
}
} else {
// 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 attribut
}
}
// Compare newAttr and currentAttr
// attribute has not changed
} else {
if(hasReauthenticated){
//already reauthed continue with attr change
} else {
// check header to make sure that password is there then check to see if it's correct
if(strCurrentPass != null && !strCurrentPass.isEmpty() && checkValidPassword(resourceId, strCurrentPass.toCharArray(), realm)){
//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 protected attribute (" + protectedAttr + ") from '" + currentAttr + "' to '" + newAttr + "'");
}
}
}
}
}
}
}
// update resource with new details
// read updated identity back to client
IdentityDetails checkIdent = idsvc.read(dtls.getName(), getIdentityServicesAttributes(realm), admin);
// handle updated resource
} catch (final ObjectNotFound onf) {
onf);
handler.handleError(new NotFoundException("Could not find the resource [ " + resourceId + " ] to update", onf));
} catch (final NeedMoreCredentials needMoreCredentials) {
} catch (final TokenExpired tokenExpired) {
} catch (final AccessDenied accessDenied) {
} catch (final GeneralFailure generalFailure) {
} catch (BadRequestException bre){
}
}
return identityServicesAttributes;
}
} else {
return toEncode;
}
}
}