usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject [79/81] [abbrv] Merge branch 'master' into two-dot-o
Date Thu, 13 Feb 2014 13:22:11 GMT
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/fb5f8d6c/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --cc stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index 0000000,ec67483..16835dd
mode 000000,100644..100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@@ -1,0 -1,2890 +1,2923 @@@
+ /*******************************************************************************
+  * Copyright 2012 Apigee Corporation
+  *
+  *
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at
+  *
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  ******************************************************************************/
+ package org.apache.usergrid.management.cassandra;
+ 
+ 
+ import java.nio.ByteBuffer;
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.HashMap;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Map.Entry;
+ import java.util.Properties;
+ import java.util.Set;
+ import java.util.UUID;
+ 
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.springframework.beans.factory.annotation.Autowired;
+ import org.apache.usergrid.locking.Lock;
+ import org.apache.usergrid.locking.LockManager;
+ import org.apache.usergrid.management.AccountCreationProps;
+ import org.apache.usergrid.management.ActivationState;
+ import org.apache.usergrid.management.ApplicationInfo;
+ import org.apache.usergrid.management.ManagementService;
+ import org.apache.usergrid.management.OrganizationInfo;
+ import org.apache.usergrid.management.OrganizationOwnerInfo;
+ import org.apache.usergrid.management.UserInfo;
+ import org.apache.usergrid.management.exceptions.DisabledAdminUserException;
+ import org.apache.usergrid.management.exceptions.DisabledAppUserException;
+ import org.apache.usergrid.management.exceptions.IncorrectPasswordException;
+ import org.apache.usergrid.management.exceptions.ManagementException;
+ import org.apache.usergrid.management.exceptions.RecentlyUsedPasswordException;
+ import org.apache.usergrid.management.exceptions.UnableToLeaveOrganizationException;
+ import org.apache.usergrid.management.exceptions.UnactivatedAdminUserException;
+ import org.apache.usergrid.management.exceptions.UnactivatedAppUserException;
+ import org.apache.usergrid.management.exceptions.UnconfirmedAdminUserException;
+ import org.apache.usergrid.persistence.CredentialsInfo;
+ import org.apache.usergrid.persistence.Entity;
+ import org.apache.usergrid.persistence.EntityManager;
+ import org.apache.usergrid.persistence.EntityManagerFactory;
+ import org.apache.usergrid.persistence.EntityRef;
+ import org.apache.usergrid.persistence.Identifier;
+ import org.apache.usergrid.persistence.Results;
+ import org.apache.usergrid.persistence.Results.Level;
+ import org.apache.usergrid.persistence.SimpleEntityRef;
+ import org.apache.usergrid.persistence.entities.Application;
+ import org.apache.usergrid.persistence.entities.Group;
+ import org.apache.usergrid.persistence.entities.User;
+ import org.apache.usergrid.persistence.exceptions.DuplicateUniquePropertyExistsException;
+ import org.apache.usergrid.persistence.exceptions.EntityNotFoundException;
+ import org.apache.usergrid.security.AuthPrincipalInfo;
+ import org.apache.usergrid.security.AuthPrincipalType;
+ import org.apache.usergrid.security.crypto.EncryptionService;
+ import org.apache.usergrid.security.oauth.AccessInfo;
+ import org.apache.usergrid.security.oauth.ClientCredentialsInfo;
+ import org.apache.usergrid.security.salt.SaltProvider;
+ import org.apache.usergrid.security.shiro.PrincipalCredentialsToken;
+ import org.apache.usergrid.security.shiro.credentials.ApplicationClientCredentials;
+ import org.apache.usergrid.security.shiro.credentials.OrganizationClientCredentials;
+ import org.apache.usergrid.security.shiro.principals.ApplicationPrincipal;
+ import org.apache.usergrid.security.shiro.principals.OrganizationPrincipal;
+ import org.apache.usergrid.security.shiro.utils.SubjectUtils;
+ import org.apache.usergrid.security.tokens.TokenCategory;
+ import org.apache.usergrid.security.tokens.TokenInfo;
+ import org.apache.usergrid.security.tokens.TokenService;
+ import org.apache.usergrid.security.tokens.exceptions.TokenException;
+ import org.apache.usergrid.services.ServiceAction;
+ import org.apache.usergrid.services.ServiceManager;
+ import org.apache.usergrid.services.ServiceManagerFactory;
+ import org.apache.usergrid.services.ServiceRequest;
+ import org.apache.usergrid.services.ServiceResults;
+ import org.apache.usergrid.utils.ConversionUtils;
+ import org.apache.usergrid.utils.JsonUtils;
+ import org.apache.usergrid.utils.MailUtils;
+ import org.apache.usergrid.utils.StringUtils;
+ import org.apache.usergrid.utils.UUIDUtils;
+ 
+ import org.apache.commons.codec.digest.DigestUtils;
+ import org.apache.commons.lang.text.StrSubstitutor;
+ import org.apache.shiro.UnavailableSecurityManagerException;
+ 
+ import com.google.common.collect.BiMap;
+ import com.google.common.collect.HashBiMap;
+ 
+ import static java.lang.Boolean.parseBoolean;
+ 
+ import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
+ import static org.apache.commons.codec.digest.DigestUtils.sha;
+ import static org.apache.commons.lang.StringUtils.isBlank;
+ import static org.apache.usergrid.locking.LockHelper.getUniqueUpdateLock;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_ADMIN_ACTIVATION_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_ADMIN_CONFIRMATION_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_ADMIN_RESETPW_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_ACTIVATED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_CONFIRMATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_CONFIRMED_AWAITING_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_INVITED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_PASSWORD_RESET;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ADMIN_USER_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_FOOTER;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ORGANIZATION_ACTIVATED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ORGANIZATION_CONFIRMATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_ORGANIZATION_CONFIRMED_AWAITING_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_SYSADMIN_ADMIN_ACTIVATED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_SYSADMIN_ADMIN_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_SYSADMIN_ORGANIZATION_ACTIVATED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_SYSADMIN_ORGANIZATION_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_USER_ACTIVATED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_USER_CONFIRMATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_USER_CONFIRMED_AWAITING_ACTIVATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_USER_PASSWORD_RESET;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_EMAIL_USER_PIN_REQUEST;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_MAILER_EMAIL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_ORGANIZATION_ACTIVATION_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SETUP_TEST_ACCOUNT;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_EMAIL;
++import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_ALLOWED;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_EMAIL;
++import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_NAME;
++import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_PASSWORD;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_ADMIN_USER_EMAIL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_ADMIN_USER_NAME;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_ADMIN_USER_PASSWORD;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_ADMIN_USER_USERNAME;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_APP;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_TEST_ACCOUNT_ORGANIZATION;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_USER_ACTIVATION_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_USER_CONFIRMATION_URL;
+ import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_USER_RESETPW_URL;
+ import static org.apache.usergrid.persistence.CredentialsInfo.getCredentialsSecret;
+ import static org.apache.usergrid.persistence.Schema.DICTIONARY_CREDENTIALS;
+ import static org.apache.usergrid.persistence.Schema.PROPERTY_NAME;
+ import static org.apache.usergrid.persistence.Schema.PROPERTY_PATH;
+ import static org.apache.usergrid.persistence.Schema.PROPERTY_SECRET;
+ import static org.apache.usergrid.persistence.Schema.PROPERTY_UUID;
+ import static org.apache.usergrid.persistence.cassandra.CassandraService.MANAGEMENT_APPLICATION_ID;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_ACTOR;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_ACTOR_NAME;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_CATEGORY;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_CONTENT;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_DISPLAY_NAME;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_ENTITY_TYPE;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_OBJECT;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_OBJECT_ENTITY_TYPE;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_OBJECT_NAME;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_OBJECT_TYPE;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_TITLE;
+ import static org.apache.usergrid.persistence.entities.Activity.PROPERTY_VERB;
+ import static org.apache.usergrid.security.AuthPrincipalType.ADMIN_USER;
+ import static org.apache.usergrid.security.AuthPrincipalType.APPLICATION;
+ import static org.apache.usergrid.security.AuthPrincipalType.APPLICATION_USER;
+ import static org.apache.usergrid.security.AuthPrincipalType.ORGANIZATION;
+ import static org.apache.usergrid.security.oauth.ClientCredentialsInfo.getTypeFromClientId;
+ import static org.apache.usergrid.security.oauth.ClientCredentialsInfo.getUUIDFromClientId;
+ import static org.apache.usergrid.security.tokens.TokenCategory.ACCESS;
+ import static org.apache.usergrid.security.tokens.TokenCategory.EMAIL;
+ import static org.apache.usergrid.services.ServiceParameter.parameters;
+ import static org.apache.usergrid.services.ServicePayload.payload;
+ import static org.apache.usergrid.services.ServiceResults.genericServiceResults;
+ import static org.apache.usergrid.utils.ClassUtils.cast;
+ import static org.apache.usergrid.utils.ConversionUtils.bytes;
+ import static org.apache.usergrid.utils.ConversionUtils.uuid;
+ import static org.apache.usergrid.utils.ListUtils.anyNull;
+ import static org.apache.usergrid.utils.MapUtils.hashMap;
+ import static org.apache.usergrid.utils.PasswordUtils.mongoPassword;
+ 
+ 
+ public class ManagementServiceImpl implements ManagementService {
+     private static final Logger logger = LoggerFactory.getLogger( ManagementServiceImpl.class );
+ 
+     /** Key for the user's pin */
+     protected static final String USER_PIN = "pin";
+ 
+     /** Key for the user's oauth secret */
+     protected static final String USER_TOKEN = "secret";
+ 
+     /** Key for the user's mongo password */
+     protected static final String USER_MONGO_PASSWORD = "mongo_pwd";
+ 
+     /** Key for the user's password */
+     protected static final String USER_PASSWORD = "password";
+ 
+     protected static final String USER_PASSWORD_HISTORY = "password_history";
+ 
+     private static final String TOKEN_TYPE_ACTIVATION = "activate";
+ 
+     private static final String TOKEN_TYPE_PASSWORD_RESET = "resetpw";
+ 
+     private static final String TOKEN_TYPE_CONFIRM = "confirm";
+ 
+     public static final String MANAGEMENT_APPLICATION = "management";
+ 
+     public static final String APPLICATION_INFO = "application_info";
+ 
+ 
+     public static final String OAUTH_SECRET_SALT = "super secret oauth value";
+ 
+     private static final String ORGANIZATION_PROPERTIES_DICTIONARY = "orgProperties";
+     public static final String REGISTRATION_REQUIRES_ADMIN_APPROVAL = "registration_requires_admin_approval";
+     public static final String REGISTRATION_REQUIRES_EMAIL_CONFIRMATION = "registration_requires_email_confirmation";
+     public static final String NOTIFY_ADMIN_OF_NEW_USERS = "notify_admin_of_new_users";
+ 
+     protected ServiceManagerFactory smf;
+ 
+     protected EntityManagerFactory emf;
+ 
+     protected AccountCreationPropsImpl properties;
+ 
+     protected LockManager lockManager;
+ 
+     protected TokenService tokens;
+ 
+     protected SaltProvider saltProvider;
+ 
+     @Autowired
+     protected MailUtils mailUtils;
+ 
+     protected EncryptionService encryptionService;
+ 
+ 
+     /** Must be constructed with a CassandraClientPool. */
+     public ManagementServiceImpl() {
+     }
+ 
+ 
+     @Autowired
+     public void setEntityManagerFactory( EntityManagerFactory emf ) {
+         logger.info( "ManagementServiceImpl.setEntityManagerFactory" );
+         this.emf = emf;
+     }
+ 
+ 
+     @Autowired
+     public void setProperties( Properties properties ) {
+         this.properties = new AccountCreationPropsImpl( properties );
+     }
+ 
+ 
+     /** For testing purposes only */
+     public Properties getProperties() {
+         return properties.properties;
+     }
+ 
+ 
+     @Autowired
+     public void setTokenService( TokenService tokens ) {
+         this.tokens = tokens;
+     }
+ 
+ 
+     @Autowired
+     public void setServiceManagerFactory( ServiceManagerFactory smf ) {
+         this.smf = smf;
+     }
+ 
+ 
+     public LockManager getLockManager() {
+         return lockManager;
+     }
+ 
+ 
+     @Autowired
+     public void setLockManager( LockManager lockManager ) {
+         this.lockManager = lockManager;
+     }
+ 
+ 
+     /** @param encryptionService the encryptionService to set */
+     @Autowired
+     public void setEncryptionService( EncryptionService encryptionService ) {
+         this.encryptionService = encryptionService;
+     }
+ 
+ 
+     @Override
+     public void setup() throws Exception {
+ 
 -        if ( parseBoolean( properties.getProperty( PROPERTIES_SETUP_TEST_ACCOUNT ) ) ) {
++        if ( getBooleanProperty( PROPERTIES_SETUP_TEST_ACCOUNT ) ) {
+             String test_app_name = properties.getProperty( PROPERTIES_TEST_ACCOUNT_APP );
+             String test_organization_name = properties.getProperty( PROPERTIES_TEST_ACCOUNT_ORGANIZATION );
+             String test_admin_username = properties.getProperty( PROPERTIES_TEST_ACCOUNT_ADMIN_USER_USERNAME );
+             String test_admin_name = properties.getProperty( PROPERTIES_TEST_ACCOUNT_ADMIN_USER_NAME );
+             String test_admin_email = properties.getProperty( PROPERTIES_TEST_ACCOUNT_ADMIN_USER_EMAIL );
+             String test_admin_password = properties.getProperty( PROPERTIES_TEST_ACCOUNT_ADMIN_USER_PASSWORD );
+ 
+             if ( anyNull( test_app_name, test_organization_name, test_admin_username, test_admin_name, test_admin_email,
+                     test_admin_password ) ) {
+                 logger.warn( "Missing values for test app, check properties.  Skipping test app setup..." );
+                 return;
+             }
+ 
+             OrganizationInfo organization = getOrganizationByName( test_organization_name );
+ 
+             if ( organization == null ) {
+                 OrganizationOwnerInfo created =
+                         createOwnerAndOrganization( test_organization_name, test_admin_username, test_admin_name,
+                                 test_admin_email, test_admin_password, true, false );
+                 organization = created.getOrganization();
+             }
+ 
+             if ( !getApplicationsForOrganization( organization.getUuid() ).containsValue( test_app_name ) ) {
+                 createApplication( organization.getUuid(), test_app_name );
+             }
+         }
+         else {
+             logger.warn( "Test app creation disabled" );
+         }
+ 
 -        if ( properties.getSuperUser().isEnabled() ) {
++        if ( superuserEnabled() ) {
+             provisionSuperuser();
+         }
+     }
+ 
+ 
++    public boolean superuserEnabled() {
++        boolean superuser_enabled = getBooleanProperty( PROPERTIES_SYSADMIN_LOGIN_ALLOWED );
++        String superuser_username = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_NAME );
++        String superuser_email = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL );
++        String superuser_password = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_PASSWORD );
++
++        return superuser_enabled && !anyNull( superuser_username, superuser_email, superuser_password );
++    }
++
++
+     @Override
+     public void provisionSuperuser() throws Exception {
 -        final AccountCreationProps.SuperUser superUser = properties.getSuperUser();
 -        if ( superUser.isEnabled() ) {
 -            UserInfo user = this.getAdminUserByUsername( superUser.getUsername() );
++        boolean superuser_enabled = getBooleanProperty( PROPERTIES_SYSADMIN_LOGIN_ALLOWED );
++        String superuser_username = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_NAME );
++        String superuser_email = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL );
++        String superuser_password = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_PASSWORD );
++
++        if ( !anyNull( superuser_username, superuser_email, superuser_password ) ) {
++            UserInfo user = this.getAdminUserByUsername( superuser_username );
+             if ( user == null ) {
 -                createAdminUser( superUser.getUsername(), "Super User", superUser.getEmail(), superUser.getPassword(),
 -                        superUser.isEnabled(), !superUser.isEnabled() );
++                createAdminUser( superuser_username, "Super User", superuser_email, superuser_password,
++                        superuser_enabled, !superuser_enabled );
+             }
+             else {
 -                this.setAdminUserPassword( user.getUuid(), superUser.getPassword() );
++                this.setAdminUserPassword( user.getUuid(), superuser_password );
+             }
+         }
+         else {
+             logger.warn(
+                     "Missing values for superuser account, check properties.  Skipping superuser account setup..." );
+         }
+     }
+ 
+ 
+     public String generateOAuthSecretKey( AuthPrincipalType type ) {
+         long timestamp = System.currentTimeMillis();
+         ByteBuffer bytes = ByteBuffer.allocate( 20 );
+         bytes.put( sha( timestamp + OAUTH_SECRET_SALT + UUID.randomUUID() ) );
+         String secret = type.getBase64Prefix() + encodeBase64URLSafeString( bytes.array() );
+         return secret;
+     }
+ 
+ 
+     @SuppressWarnings( "serial" )
+     @Override
+     public void postOrganizationActivity( UUID organizationId, final UserInfo user, String verb, final EntityRef object,
+                                           final String objectType, final String objectName, String title,
+                                           String content ) throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+ 
+         Map<String, Object> properties = new HashMap<String, Object>();
+         properties.put( PROPERTY_VERB, verb );
+         properties.put( PROPERTY_CATEGORY, "admin" );
+         if ( content != null ) {
+             properties.put( PROPERTY_CONTENT, content );
+         }
+         if ( title != null ) {
+             properties.put( PROPERTY_TITLE, title );
+         }
+         properties.put( PROPERTY_ACTOR, new HashMap<String, Object>() {
+             {
+                 put( PROPERTY_DISPLAY_NAME, user.getName() );
+                 put( PROPERTY_OBJECT_TYPE, "person" );
+                 put( PROPERTY_ENTITY_TYPE, "user" );
+                 put( PROPERTY_UUID, user.getUuid() );
+             }
+         } );
+         properties.put( PROPERTY_OBJECT, new HashMap<String, Object>() {
+             {
+                 put( PROPERTY_DISPLAY_NAME, objectName );
+                 put( PROPERTY_OBJECT_TYPE, objectType );
+                 put( PROPERTY_ENTITY_TYPE, object.getType() );
+                 put( PROPERTY_UUID, object.getUuid() );
+             }
+         } );
+ 
+         sm.newRequest( ServiceAction.POST, parameters( "groups", organizationId, "activities" ), payload( properties ) )
+           .execute().getEntity();
+     }
+ 
+ 
+     @Override
+     public ServiceResults getOrganizationActivity( OrganizationInfo organization ) throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+         return sm.newRequest( ServiceAction.GET, parameters( "groups", organization.getUuid(), "feed" ) ).execute();
+     }
+ 
+ 
+     @Override
+     public ServiceResults getOrganizationActivityForAdminUser( OrganizationInfo organization, UserInfo user )
+             throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+         return sm.newRequest( ServiceAction.GET,
+                 parameters( "groups", organization.getUuid(), "users", user.getUuid(), "feed" ) ).execute();
+     }
+ 
+ 
+     @Override
+     public ServiceResults getAdminUserActivity( UserInfo user ) throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+         return sm.newRequest( ServiceAction.GET, parameters( "users", user.getUuid(), "feed" ) ).execute();
+     }
+ 
+ 
+     @Override
+     public OrganizationOwnerInfo createOwnerAndOrganization( String organizationName, String username, String name,
+                                                              String email, String password ) throws Exception {
+ 
+         boolean activated = !newAdminUsersNeedSysAdminApproval() && !newOrganizationsNeedSysAdminApproval();
+         boolean disabled = newAdminUsersRequireConfirmation();
+         // if we are active and enabled, skip the send email step
+ 
+         return createOwnerAndOrganization( organizationName, username, name, email, password, activated, disabled, null,
+                 null );
+     }
+ 
+ 
+     @Override
+     public OrganizationOwnerInfo createOwnerAndOrganization( String organizationName, String username, String name,
+                                                              String email, String password, boolean activated,
+                                                              boolean disabled ) throws Exception {
+         return createOwnerAndOrganization( organizationName, username, name, email, password, activated, disabled, null,
+                 null );
+     }
+ 
+ 
+     @Override
+     public OrganizationOwnerInfo createOwnerAndOrganization( String organizationName, String username, String name,
+                                                              String email, String password, boolean activated,
+                                                              boolean disabled, Map<String, Object> userProperties,
+                                                              Map<String, Object> organizationProperties )
+             throws Exception {
+ 
+         /**
+          * Only lock on the target values. We don't want lock contention if another
+          * node is trying to set the property do a different value
+          */
+         Lock groupLock =
+                 getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, organizationName, "groups", "path" );
+ 
+         Lock userLock = getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, username, "users", "username" );
+ 
+         Lock emailLock = getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, email, "users", "email" );
+ 
+         UserInfo user = null;
+         OrganizationInfo organization = null;
+ 
+         try {
+ 
+             groupLock.lock();
+             userLock.lock();
+             emailLock.lock();
+             EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+             if ( !em.isPropertyValueUniqueForEntity( "group", "path", organizationName ) ) {
+                 throw new DuplicateUniquePropertyExistsException( "group", "path", organizationName );
+             }
+             if ( !validateAdminInfo( username, name, email, password ) ) {
+                 return null;
+             }
+             if ( areActivationChecksDisabled() ) {
+                 user = createAdminUserInternal( username, name, email, password, true, false, userProperties );
+             }
+             else {
+                 user = createAdminUserInternal( username, name, email, password, activated, disabled, userProperties );
+             }
+ 
+             organization = createOrganizationInternal( organizationName, user, true, organizationProperties );
+         }
+         finally {
+             emailLock.unlock();
+             userLock.unlock();
+             groupLock.unlock();
+         }
+ 
+         return new OrganizationOwnerInfo( user, organization );
+     }
+ 
+ 
+     private OrganizationInfo createOrganizationInternal( String organizationName, UserInfo user, boolean activated )
+             throws Exception {
+         return createOrganizationInternal( organizationName, user, activated, null );
+     }
+ 
+ 
+     private OrganizationInfo createOrganizationInternal( String organizationName, UserInfo user, boolean activated,
+                                                          Map<String, Object> properties ) throws Exception {
+         if ( ( organizationName == null ) || ( user == null ) ) {
+             return null;
+         }
+         logger.info( "createOrganizationInternal: {}", organizationName );
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ 
+         Group organizationEntity = new Group();
+         organizationEntity.setPath( organizationName );
+         organizationEntity = em.create( organizationEntity );
+ 
+         em.addToCollection( organizationEntity, "users", new SimpleEntityRef( User.ENTITY_TYPE, user.getUuid() ) );
+ 
+         writeUserToken( MANAGEMENT_APPLICATION_ID, organizationEntity, encryptionService
+                 .plainTextCredentials( generateOAuthSecretKey( AuthPrincipalType.ORGANIZATION ), user.getUuid(),
+                         MANAGEMENT_APPLICATION_ID ) );
+ 
+         OrganizationInfo organization =
+                 new OrganizationInfo( organizationEntity.getUuid(), organizationName, properties );
+         updateOrganization( organization );
+ 
+         logger.info( "createOrganizationInternal: {}", organizationName );
+         postOrganizationActivity( organization.getUuid(), user, "create", organizationEntity, "Organization",
+                 organization.getName(),
+                 "<a href=\"mailto:" + user.getEmail() + "\">" + user.getName() + " (" + user.getEmail()
+                         + ")</a> created a new organization account named " + organizationName, null );
+ 
+         startOrganizationActivationFlow( organization );
+ 
+         return organization;
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo createOrganization( String organizationName, UserInfo user, boolean activated )
+             throws Exception {
+ 
+         if ( ( organizationName == null ) || ( user == null ) ) {
+             return null;
+         }
+         Lock groupLock =
+                 getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, organizationName, "groups", "path" );
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         if ( !em.isPropertyValueUniqueForEntity( "group", "path", organizationName ) ) {
+             throw new DuplicateUniquePropertyExistsException( "group", "path", organizationName );
+         }
+         try {
+             groupLock.lock();
+             return createOrganizationInternal( organizationName, user, activated );
+         }
+         finally {
+             groupLock.unlock();
+         }
+     }
+ 
+ 
+     /** currently only affects properties */
+     public void updateOrganization( OrganizationInfo organizationInfo ) throws Exception {
+         Map<String, Object> properties = organizationInfo.getProperties();
+         if ( properties != null ) {
+             EntityRef organizationEntity = new SimpleEntityRef( organizationInfo.getUuid() );
+             EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+             for ( Map.Entry<String, Object> entry : properties.entrySet() ) {
+                 if ( "".equals( entry.getValue() ) ) {
+                     properties.remove( entry.getKey() );
+                     em.removeFromDictionary( organizationEntity, ORGANIZATION_PROPERTIES_DICTIONARY, entry.getKey() );
+                 }
+                 else {
+                     em.addToDictionary( organizationEntity, ORGANIZATION_PROPERTIES_DICTIONARY, entry.getKey(),
+                             entry.getValue() );
+                 }
+             }
+         }
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo importOrganization( UUID organizationId, OrganizationInfo organizationInfo,
+                                                 Map<String, Object> properties ) throws Exception {
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         if ( !em.isPropertyValueUniqueForEntity( "group", "path", organizationInfo.getName() ) ) {
+             throw new DuplicateUniquePropertyExistsException( "group", "path", organizationInfo.getName() );
+         }
+         if ( properties == null ) {
+             properties = new HashMap<String, Object>();
+         }
+ 
+         String organizationName = null;
+         if ( organizationInfo != null ) {
+             organizationName = organizationInfo.getName();
+         }
+         if ( organizationName == null ) {
+             organizationName = ( String ) properties.get( PROPERTY_PATH );
+         }
+         if ( organizationName == null ) {
+             organizationName = ( String ) properties.get( PROPERTY_NAME );
+         }
+         if ( organizationName == null ) {
+             return null;
+         }
+ 
+         if ( organizationId == null ) {
+             if ( organizationInfo != null ) {
+                 organizationId = organizationInfo.getUuid();
+             }
+         }
+         if ( organizationId == null ) {
+             organizationId = uuid( properties.get( PROPERTY_UUID ) );
+         }
+         if ( organizationId == null ) {
+             return null;
+         }
+ 
+         properties.put( PROPERTY_PATH, organizationName );
+         properties.put( PROPERTY_SECRET, generateOAuthSecretKey( AuthPrincipalType.ORGANIZATION ) );
+         Entity organization = em.create( organizationId, Group.ENTITY_TYPE, properties );
+         // em.addToCollection(organization, "users", new SimpleEntityRef(
+         // User.ENTITY_TYPE, userId));
+         return new OrganizationInfo( organization.getUuid(), organizationName );
+     }
+ 
+ 
+     @Override
+     public UUID importApplication( UUID organizationId, Application application ) throws Exception {
+         // TODO organizationName
+         OrganizationInfo organization = getOrganizationByUuid( organizationId );
+         UUID applicationId =
+                 emf.importApplication( organization.getName(), application.getUuid(), application.getName(),
+                         application.getProperties() );
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         properties.setProperty( "name", buildAppName( application.getName(), organization ) );
+         Entity app = em.create( applicationId, APPLICATION_INFO, application.getProperties() );
+ 
+         writeUserToken( MANAGEMENT_APPLICATION_ID, app, encryptionService
+                 .plainTextCredentials( generateOAuthSecretKey( AuthPrincipalType.APPLICATION ), null, applicationId ) );
+ 
+         addApplicationToOrganization( organizationId, applicationId );
+         return applicationId;
+     }
+ 
+ 
+     /**
+      * Test if the applicationName contains a '/' character, prepend with orgName if it does not, assume it is complete
+      * (and that organization is needed) if so.
+      */
+     private String buildAppName( String applicationName, OrganizationInfo organization ) {
+         return applicationName.contains( "/" ) ? applicationName : organization.getName() + "/" + applicationName;
+     }
+ 
+ 
+     @Override
+     public List<OrganizationInfo> getOrganizations( UUID startResult, int count ) throws Exception {
+         // still need the bimap to search for existing
+         BiMap<UUID, String> organizations = HashBiMap.create();
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Results results =
+                 em.getCollection( em.getApplicationRef(), "groups", startResult, count, Level.ALL_PROPERTIES, false );
+         List<OrganizationInfo> orgs = new ArrayList<OrganizationInfo>( results.size() );
+         OrganizationInfo orgInfo;
+         for ( Entity entity : results.getEntities() ) {
+             // TODO T.N. temporary hack to deal with duplicate orgs. Revert this
+             // commit after migration
+             String path = ( String ) entity.getProperty( "path" );
+ 
+             if ( organizations.containsValue( path ) ) {
+                 path += "DUPLICATE";
+             }
+             orgInfo = new OrganizationInfo( entity.getUuid(), path );
+             orgs.add( orgInfo );
+             organizations.put( entity.getUuid(), path );
+         }
+         return orgs;
+     }
+ 
+ 
+     @Override
+     public BiMap<UUID, String> getOrganizations() throws Exception {
+         List<OrganizationInfo> orgs = getOrganizations( null, 10000 );
+         return buildOrgBiMap( orgs );
+     }
+ 
+ 
+     private BiMap<UUID, String> buildOrgBiMap( List<OrganizationInfo> orgs ) {
+         BiMap<UUID, String> organizations = HashBiMap.create();
+         for ( OrganizationInfo orgInfo : orgs ) {
+             organizations.put( orgInfo.getUuid(), orgInfo.getName() );
+         }
+         return organizations;
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo getOrganizationInfoFromAccessToken( String token ) throws Exception {
+         Entity entity = getEntityFromAccessToken( token, null, ORGANIZATION );
+         if ( entity == null ) {
+             return null;
+         }
+         return new OrganizationInfo( entity.getProperties() );
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo getOrganizationByName( String organizationName ) throws Exception {
+ 
+         if ( organizationName == null ) {
+             return null;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         EntityRef ref = em.getAlias( "group", organizationName );
+         if ( ref == null ) {
+             return null;
+         }
+         return getOrganizationByUuid( ref.getUuid() );
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo getOrganizationByUuid( UUID id ) throws Exception {
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Entity entity = em.get( new SimpleEntityRef( Group.ENTITY_TYPE, id ) );
+         if ( entity == null ) {
+             return null;
+         }
+         Map properties = em.getDictionaryAsMap( entity, ORGANIZATION_PROPERTIES_DICTIONARY );
+         OrganizationInfo orgInfo = new OrganizationInfo( entity.getProperties() );
+         orgInfo.setProperties( properties );
+         return orgInfo;
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo getOrganizationByIdentifier( Identifier id ) throws Exception {
+         if ( id.isUUID() ) {
+             return getOrganizationByUuid( id.getUUID() );
+         }
+         if ( id.isName() ) {
+             return getOrganizationByName( id.getName() );
+         }
+         return null;
+     }
+ 
+ 
+     public void postUserActivity( UserInfo user, String verb, EntityRef object, String objectType, String objectName,
+                                   String title, String content ) throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+ 
+         Map<String, Object> properties = new HashMap<String, Object>();
+         properties.put( PROPERTY_VERB, verb );
+         properties.put( PROPERTY_CATEGORY, "admin" );
+         if ( content != null ) {
+             properties.put( PROPERTY_CONTENT, content );
+         }
+         if ( title != null ) {
+             properties.put( PROPERTY_TITLE, title );
+         }
+         properties.put( PROPERTY_ACTOR, user.getUuid() );
+         properties.put( PROPERTY_ACTOR_NAME, user.getName() );
+         properties.put( PROPERTY_OBJECT, object.getUuid() );
+         properties.put( PROPERTY_OBJECT_ENTITY_TYPE, object.getType() );
+         properties.put( PROPERTY_OBJECT_TYPE, objectType );
+         properties.put( PROPERTY_OBJECT_NAME, objectName );
+ 
+         sm.newRequest( ServiceAction.POST, parameters( "users", user.getUuid(), "activities" ), payload( properties ) )
+           .execute().getEntity();
+     }
+ 
+ 
+     @Override
+     public ServiceResults getAdminUserActivities( UserInfo user ) throws Exception {
+         ServiceManager sm = smf.getServiceManager( MANAGEMENT_APPLICATION_ID );
+         ServiceRequest request = sm.newRequest( ServiceAction.GET, parameters( "users", user.getUuid(), "feed" ) );
+         ServiceResults results = request.execute();
+         return results;
+     }
+ 
+ 
+     private UserInfo doCreateAdmin( User user, CredentialsInfo userPassword, CredentialsInfo mongoPassword )
+             throws Exception {
+ 
+         writeUserToken( MANAGEMENT_APPLICATION_ID, user, encryptionService
+                 .plainTextCredentials( generateOAuthSecretKey( AuthPrincipalType.ADMIN_USER ), user.getUuid(),
+                         MANAGEMENT_APPLICATION_ID ) );
+ 
+         writeUserPassword( MANAGEMENT_APPLICATION_ID, user, userPassword );
+ 
+         writeUserMongoPassword( MANAGEMENT_APPLICATION_ID, user, mongoPassword );
+ 
+         UserInfo userInfo = new UserInfo( MANAGEMENT_APPLICATION_ID, user.getUuid(), user.getUsername(), user.getName(),
+                 user.getEmail(), user.getConfirmed(), user.getActivated(), user.getDisabled(),
+                 user.getDynamicProperties() );
+ 
+         // special case for sysadmin and test account only
+         if ( !user.getEmail().equals( properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL ) ) && !user.getEmail()
+                                                                                                           .equals(
+                                                                                                                   properties
+                                                                                                                           .getProperty(
+                                                                                                                                   PROPERTIES_TEST_ACCOUNT_ADMIN_USER_EMAIL ) ) ) {
+             this.startAdminUserActivationFlow( userInfo );
+         }
+ 
+         return userInfo;
+     }
+ 
+ 
+     @Override
+     public UserInfo createAdminFromPrexistingPassword( User user, CredentialsInfo ci ) throws Exception {
+ 
+         return doCreateAdmin( user, ci,
+                 // we can't actually set the mongo password. We never have the plain text in
+                 // this path
+                 encryptionService.plainTextCredentials( mongoPassword( user.getUsername(), "" ), user.getUuid(),
+                         MANAGEMENT_APPLICATION_ID ) );
+     }
+ 
+ 
+     @Override
+     public UserInfo createAdminFrom( User user, String password ) throws Exception {
+         return doCreateAdmin( user,
+                 encryptionService.defaultEncryptedCredentials( password, user.getUuid(), MANAGEMENT_APPLICATION_ID ),
+                 encryptionService.plainTextCredentials( mongoPassword( user.getUsername(), password ), user.getUuid(),
+                         MANAGEMENT_APPLICATION_ID ) );
+     }
+ 
+ 
+     @Override
+     public UserInfo createAdminUser( String username, String name, String email, String password, boolean activated,
+                                      boolean disabled ) throws Exception {
+         return createAdminUser( username, name, email, password, activated, disabled, null );
+     }
+ 
+ 
+     @Override
+     public UserInfo createAdminUser( String username, String name, String email, String password, boolean activated,
+                                      boolean disabled, Map<String, Object> userProperties ) throws Exception {
+         if ( !validateAdminInfo( username, name, email, password ) ) {
+             return null;
+         }
+         return createAdminUserInternal( username, name, email, password, activated, disabled, userProperties );
+     }
+ 
+ 
+     private boolean validateAdminInfo( String username, String name, String email, String password ) throws Exception {
+         if ( email == null ) {
+             return false;
+         }
+         if ( username == null ) {
+             username = email;
+         }
+         if ( name == null ) {
+             name = email;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ 
+         if ( !em.isPropertyValueUniqueForEntity( "user", "username", username ) ) {
+             throw new DuplicateUniquePropertyExistsException( "user", "username", username );
+         }
+ 
+         if ( !em.isPropertyValueUniqueForEntity( "user", "email", email ) ) {
+             throw new DuplicateUniquePropertyExistsException( "user", "email", email );
+         }
+         return true;
+     }
+ 
+ 
+     private UserInfo createAdminUserInternal( String username, String name, String email, String password,
+                                               boolean activated, boolean disabled, Map<String, Object> userProperties )
+             throws Exception {
+         logger.info( "createAdminUserInternal: {}", username );
+ 
+         if ( isBlank( password ) ) {
+             password = encodeBase64URLSafeString( bytes( UUID.randomUUID() ) );
+         }
+         if ( username == null ) {
+             username = email;
+         }
+         if ( name == null ) {
+             name = email;
+         }
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         User user = new User();
+         user.setUsername( username );
+         user.setName( name );
+         user.setEmail( email );
+         user.setActivated( activated );
+         user.setConfirmed( !newAdminUsersRequireConfirmation() ); // only
+         user.setDisabled( disabled );
+         if ( userProperties != null ) {
+             // double check no 'password' property just to be safe
+             userProperties.remove( "password" );
+             user.setProperties( userProperties );
+         }
+         user = em.create( user );
+ 
+         return createAdminFrom( user, password );
+     }
+ 
+ 
+     public UserInfo getUserInfo( UUID applicationId, Entity entity ) {
+ 
+         if ( entity == null ) {
+             return null;
+         }
+         return new UserInfo( applicationId, entity.getUuid(), ( String ) entity.getProperty( "username" ),
+                 entity.getName(), ( String ) entity.getProperty( "email" ),
+                 ConversionUtils.getBoolean( entity.getProperty( "confirmed" ) ),
+                 ConversionUtils.getBoolean( entity.getProperty( "activated" ) ),
+                 ConversionUtils.getBoolean( entity.getProperty( "disabled" ) ), entity.getDynamicProperties() );
+     }
+ 
+ 
+     public UserInfo getUserInfo( UUID applicationId, Map<String, Object> properties ) {
+ 
+         if ( properties == null ) {
+             return null;
+         }
+         return new UserInfo( applicationId, properties );
+     }
+ 
+ 
+     @Override
+     public List<UserInfo> getAdminUsersForOrganization( UUID organizationId ) throws Exception {
+ 
+         if ( organizationId == null ) {
+             return null;
+         }
+ 
+         List<UserInfo> users = new ArrayList<UserInfo>();
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Results results =
+                 em.getCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organizationId ), "users", null, 10000,
+                         Level.ALL_PROPERTIES, false );
+         for ( Entity entity : results.getEntities() ) {
+             users.add( getUserInfo( MANAGEMENT_APPLICATION_ID, entity ) );
+         }
+ 
+         return users;
+     }
+ 
+ 
+     @Override
+     public UserInfo updateAdminUser( UserInfo user, String username, String name, String email,
+                                      Map<String, Object> json ) throws Exception {
+ 
+         /**
+          * Only lock on the target values. We don't want lock contention if another
+          * node is trying to set the property do a different value
+          */
+         Lock usernameLock =
+                 getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, username, "users", "username" );
+ 
+         Lock emailLock = getUniqueUpdateLock( lockManager, MANAGEMENT_APPLICATION_ID, email, "users", "email" );
+ 
+         try {
+ 
+             usernameLock.lock();
+             emailLock.lock();
+ 
+             EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ 
+             SimpleEntityRef entityRef = new SimpleEntityRef( User.ENTITY_TYPE, user.getUuid() );
+             if ( !isBlank( username ) ) {
+                 em.setProperty( entityRef, "username", username );
+             }
+             if ( !isBlank( name ) ) {
+                 em.setProperty( entityRef, "name", name );
+             }
+             if ( !isBlank( email ) ) {
+                 em.setProperty( entityRef, "email", email );
+             }
+             if ( json != null ) {
+                 json.remove( "password" );
+                 json.remove( "oldpassword" );
+                 json.remove( "newpassword" );
+                 Map<String, Object> userProperties = user.getProperties();
+                 userProperties.putAll( json );
+                 em.updateProperties( entityRef, userProperties );
+             }
+ 
+             user = getAdminUserByUuid( user.getUuid() );
+         }
+         finally {
+             emailLock.unlock();
+             usernameLock.unlock();
+         }
+ 
+         return user;
+     }
+ 
+ 
+     public User getAdminUserEntityByEmail( String email ) throws Exception {
+ 
+         if ( email == null ) {
+             return null;
+         }
+ 
+         return getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, Identifier.fromEmail( email ) );
+     }
+ 
+ 
+     @Override
+     public UserInfo getAdminUserByEmail( String email ) throws Exception {
+         if ( email == null ) {
+             return null;
+         }
+         return getUserInfo( MANAGEMENT_APPLICATION_ID,
+                 getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, Identifier.fromEmail( email ) ) );
+     }
+ 
+ 
+     public User getUserEntityByIdentifier( UUID applicationId, Identifier indentifier ) throws Exception {
+         EntityManager em = emf.getEntityManager( applicationId );
+         return em.get( em.getUserByIdentifier( indentifier ), User.class );
+     }
+ 
+ 
+     @Override
+     public UserInfo getAdminUserByUsername( String username ) throws Exception {
+         if ( username == null ) {
+             return null;
+         }
+         return getUserInfo( MANAGEMENT_APPLICATION_ID,
+                 getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, Identifier.fromName( username ) ) );
+     }
+ 
+ 
+     @Override
+     public User getAdminUserEntityByUuid( UUID id ) throws Exception {
+         if ( id == null ) {
+             return null;
+         }
+         return getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, Identifier.fromUUID( id ) );
+     }
+ 
+ 
+     @Override
+     public UserInfo getAdminUserByUuid( UUID id ) throws Exception {
+         return getUserInfo( MANAGEMENT_APPLICATION_ID,
+                 getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, Identifier.fromUUID( id ) ) );
+     }
+ 
+ 
+     @Override
+     public User getAdminUserEntityByIdentifier( Identifier id ) throws Exception {
+         return getUserEntityByIdentifier( MANAGEMENT_APPLICATION_ID, id );
+     }
+ 
+ 
+     @Override
+     public UserInfo getAdminUserByIdentifier( Identifier id ) throws Exception {
+         if ( id.isUUID() ) {
+             return getAdminUserByUuid( id.getUUID() );
+         }
+         if ( id.isName() ) {
+             return getAdminUserByUsername( id.getName() );
+         }
+         if ( id.isEmail() ) {
+             return getAdminUserByEmail( id.getEmail() );
+         }
+         return null;
+     }
+ 
+ 
+     public User findUserEntity( UUID applicationId, String identifier ) {
+ 
+         User user = null;
+         if ( UUIDUtils.isUUID( identifier ) ) {
+             try {
+                 Entity entity = getUserEntityByIdentifier( applicationId,
+                         Identifier.fromUUID( UUID.fromString( identifier ) ) );
+                 if ( entity != null ) {
+                     user = ( User ) entity.toTypedEntity();
+                     logger.info( "Found user {} as a UUID", identifier );
+                 }
+             }
+             catch ( Exception e ) {
+                 logger.warn( "Unable to get user " + identifier + " as a UUID, trying username..." );
+             }
+             return user;
+         }
+         // now we are either an email or a username. Let Indentifier handle the parsing of such.
+         Identifier id = Identifier.from( identifier );
+ 
+         try {
+             Entity entity = getUserEntityByIdentifier( applicationId, id );
+             if ( entity != null ) {
+                 user = ( User ) entity.toTypedEntity();
+                 logger.info( "Found user {} as an {}", identifier, id.getType() );
+             }
+         }
+         catch ( Exception e ) {
+             logger.warn( "Unable to get user {} as a {}", identifier, id.getType() );
+         }
+         if ( user != null ) {
+             return user;
+         }
+ 
+         return null;
+     }
+ 
+ 
+     @Override
+     public UserInfo findAdminUser( String identifier ) {
+         return getUserInfo( MANAGEMENT_APPLICATION_ID, findUserEntity( MANAGEMENT_APPLICATION_ID, identifier ) );
+     }
+ 
+ 
+     @Override
+     public void setAdminUserPassword( UUID userId, String oldPassword, String newPassword ) throws Exception {
+ 
+         if ( ( userId == null ) || ( oldPassword == null ) || ( newPassword == null ) ) {
+             return;
+         }
+         User user = emf.getEntityManager( MANAGEMENT_APPLICATION_ID ).get( userId, User.class );
+ 
+         if ( !verify( MANAGEMENT_APPLICATION_ID, user.getUuid(), oldPassword ) ) {
+             logger.info( "Old password doesn't match" );
+             throw new IncorrectPasswordException( "Old password does not match" );
+         }
+ 
+         setAdminUserPassword( userId, newPassword );
+     }
+ 
+ 
+     private static final String CREDENTIALS_HISTORY = "credentialsHistory";
+ 
+ 
+     @Override
+     public void setAdminUserPassword( UUID userId, String newPassword ) throws Exception {
+ 
+         if ( ( userId == null ) || ( newPassword == null ) ) {
+             return;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         User user = em.get( userId, User.class );
+ 
+         CredentialsInfo newCredentials =
+                 encryptionService.defaultEncryptedCredentials( newPassword, user.getUuid(), MANAGEMENT_APPLICATION_ID );
+ 
+         int passwordHistorySize = calculatePasswordHistorySizeForUser( user.getUuid() );
+         Map<String, CredentialsInfo> credsMap = cast( em.getDictionaryAsMap( user, CREDENTIALS_HISTORY ) );
+ 
+         CredentialsInfo currentCredentials = null;
+         if ( passwordHistorySize > 0 ) {
+             ArrayList<CredentialsInfo> oldCreds = new ArrayList<CredentialsInfo>( credsMap.values() );
+             Collections.sort( oldCreds );
+ 
+             currentCredentials = readUserPasswordCredentials( MANAGEMENT_APPLICATION_ID, user.getUuid() );
+ 
+             // check credential history
+             if ( encryptionService.verify( newPassword, currentCredentials, userId, MANAGEMENT_APPLICATION_ID ) ) {
+                 throw new RecentlyUsedPasswordException();
+             }
+             for ( int i = 0; i < oldCreds.size() && i < passwordHistorySize; i++ ) {
+                 CredentialsInfo ci = oldCreds.get( i );
+                 if ( encryptionService.verify( newPassword, ci, userId, MANAGEMENT_APPLICATION_ID ) ) {
+                     throw new RecentlyUsedPasswordException();
+                 }
+             }
+         }
+ 
+         // remove excess history
+         if ( credsMap.size() > passwordHistorySize ) {
+             ArrayList<UUID> oldUUIDs = new ArrayList<UUID>( credsMap.size() );
+             for ( String uuid : credsMap.keySet() ) {
+                 oldUUIDs.add( UUID.fromString( uuid ) );
+             }
+             UUIDUtils.sort( oldUUIDs );
+             for ( int i = 0; i < oldUUIDs.size() - passwordHistorySize; i++ ) {
+                 em.removeFromDictionary( user, CREDENTIALS_HISTORY, oldUUIDs.get( i ).toString() );
+             }
+         }
+ 
+         if ( passwordHistorySize > 0 ) {
+             UUID uuid = UUIDUtils.newTimeUUID();
+             em.addToDictionary( user, CREDENTIALS_HISTORY, uuid.toString(), currentCredentials );
+         }
+ 
+         writeUserPassword( MANAGEMENT_APPLICATION_ID, user, newCredentials );
+         writeUserMongoPassword( MANAGEMENT_APPLICATION_ID, user, encryptionService
+                 .plainTextCredentials( mongoPassword( ( String ) user.getProperty( "username" ), newPassword ),
+                         user.getUuid(), MANAGEMENT_APPLICATION_ID ) );
+     }
+ 
+ 
+     public int calculatePasswordHistorySizeForUser( UUID userId ) throws Exception {
+ 
+         int size = 0;
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ 
+         Results orgResults =
+                 em.getCollection( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "groups", null, 10000, Level.REFS,
+                         false );
+ 
+         for ( EntityRef orgRef : orgResults.getRefs() ) {
+             Map properties = em.getDictionaryAsMap( orgRef, ORGANIZATION_PROPERTIES_DICTIONARY );
+             if ( properties != null ) {
+                 size = Math.max( new OrganizationInfo( null, null, properties ).getPasswordHistorySize(), size );
+             }
+         }
+ 
+         return size;
+     }
+ 
+ 
+     @Override
+     public boolean verifyAdminUserPassword( UUID userId, String password ) throws Exception {
+         if ( ( userId == null ) || ( password == null ) ) {
+             return false;
+         }
+         User user = emf.getEntityManager( MANAGEMENT_APPLICATION_ID ).get( userId, User.class );
+ 
+         return verify( MANAGEMENT_APPLICATION_ID, user.getUuid(), password );
+     }
+ 
+ 
+     @Override
+     public UserInfo verifyAdminUserPasswordCredentials( String name, String password ) throws Exception {
+         UserInfo userInfo = null;
+ 
+         User user = findUserEntity( MANAGEMENT_APPLICATION_ID, name );
+         if ( user == null ) {
+             return null;
+         }
+ 
+         if ( verify( MANAGEMENT_APPLICATION_ID, user.getUuid(), password ) ) {
+             userInfo = getUserInfo( MANAGEMENT_APPLICATION_ID, user );
+ 
 -            boolean userIsSuperAdmin = properties.getSuperUser().isEnabled() && properties.getSuperUser().getEmail().equals(userInfo.getEmail());
 -
 -            boolean testUserEnabled = parseBoolean( properties.getProperty( PROPERTIES_SETUP_TEST_ACCOUNT ) );
++            boolean userIsSuperAdmin =
++                    StringUtils.equals( getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL ), userInfo.getEmail() );
++            boolean testUserEnabled = getBooleanProperty( PROPERTIES_SETUP_TEST_ACCOUNT );
+ 
+             boolean userIsTestUser = !testUserEnabled ? false :
 -                    properties.getProperty( PROPERTIES_TEST_ACCOUNT_ADMIN_USER_EMAIL )
 -                            .equals( userInfo.getEmail() );
++                    StringUtils.equals(getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL ), userInfo.getEmail());
+ 
+             if ( !userIsSuperAdmin && !userIsTestUser ) {
+ 
+                 if ( !userInfo.isConfirmed() && newAdminUsersRequireConfirmation() ) {
+                     throw new UnconfirmedAdminUserException();
+                 }
+                 if ( !userInfo.isActivated() ) {
+                     throw new UnactivatedAdminUserException();
+                 }
+                 if ( userInfo.isDisabled() ) {
+                     throw new DisabledAdminUserException();
+                 }
+             }
+             return userInfo;
+         }
+         logger.info( "password compare fail for {}", name );
+         return null;
+     }
+ 
+ 
+     @Override
+     public UserInfo verifyMongoCredentials( String name, String nonce, String key ) throws Exception {
+ 
+         Entity user = findUserEntity( MANAGEMENT_APPLICATION_ID, name );
+ 
+         if ( user == null ) {
+             return null;
+         }
+ 
+         String mongo_pwd = readUserMongoPassword( MANAGEMENT_APPLICATION_ID, user.getUuid() ).getSecret();
+ 
+         if ( mongo_pwd == null ) {
+             throw new IncorrectPasswordException( "Your mongo password has not be set" );
+         }
+ 
+         String expected_key = DigestUtils.md5Hex( nonce + user.getProperty( "username" ) + mongo_pwd );
+ 
+         if ( !expected_key.equalsIgnoreCase( key ) ) {
+             throw new IncorrectPasswordException();
+         }
+ 
+         UserInfo userInfo = new UserInfo( MANAGEMENT_APPLICATION_ID, user.getProperties() );
+ 
+         if ( !userInfo.isActivated() ) {
+             throw new UnactivatedAdminUserException();
+         }
+         if ( userInfo.isDisabled() ) {
+             throw new DisabledAdminUserException();
+         }
+ 
+         return userInfo;
+     }
+ 
+ 
+     // TokenType tokenType, String type, AuthPrincipalInfo principal,
+     // Map<String, Object> state
+     public String getTokenForPrincipal( TokenCategory token_category, String token_type, UUID applicationId,
+                                         AuthPrincipalType principal_type, UUID id, long duration ) throws Exception {
+ 
+         if ( anyNull( token_category, applicationId, principal_type, id ) ) {
+             return null;
+         }
+ 
+         return tokens
+                 .createToken( token_category, token_type, new AuthPrincipalInfo( principal_type, id, applicationId ),
+                         null, duration );
+     }
+ 
+ 
+     public void revokeTokensForPrincipal( AuthPrincipalType principalType, UUID applicationId, UUID id )
+             throws Exception {
+ 
+         if ( anyNull( applicationId, principalType, id ) ) {
+             throw new IllegalArgumentException( "applicationId, principal_type and id are required" );
+         }
+ 
+         AuthPrincipalInfo principal = new AuthPrincipalInfo( principalType, id, applicationId );
+ 
+         tokens.removeTokens( principal );
+     }
+ 
+ 
+     public AuthPrincipalInfo getPrincipalFromAccessToken( String token, String expected_token_type,
+                                                           AuthPrincipalType expected_principal_type ) throws Exception {
+ 
+         TokenInfo tokenInfo = tokens.getTokenInfo( token );
+ 
+         if ( tokenInfo == null ) {
+             return null;
+         }
+ 
+         if ( ( expected_token_type != null ) && !expected_token_type.equals( tokenInfo.getType() ) ) {
+             return null;
+         }
+ 
+         AuthPrincipalInfo principal = tokenInfo.getPrincipal();
+         if ( principal == null ) {
+             return null;
+         }
+ 
+         if ( ( expected_principal_type != null ) && !expected_principal_type.equals( principal.getType() ) ) {
+             return null;
+         }
+ 
+         return principal;
+     }
+ 
+ 
+     public Entity getEntityFromAccessToken( String token, String expected_token_type,
+                                             AuthPrincipalType expected_principal_type ) throws Exception {
+ 
+         AuthPrincipalInfo principal =
+                 getPrincipalFromAccessToken( token, expected_token_type, expected_principal_type );
+         if ( principal == null ) {
+             return null;
+         }
+ 
+         return getEntityFromPrincipal( principal );
+     }
+ 
+ 
+     public Entity getEntityFromPrincipal( AuthPrincipalInfo principal ) throws Exception {
+ 
+         EntityManager em = emf.getEntityManager(
+                 principal.getApplicationId() != null ? principal.getApplicationId() : MANAGEMENT_APPLICATION_ID );
+         Entity entity = em.get( principal.getUuid() );
+         return entity;
+     }
+ 
+ 
+     @Override
+     public String getAccessTokenForAdminUser( UUID userId, long duration ) throws Exception {
+ 
+         return getTokenForPrincipal( ACCESS, null, MANAGEMENT_APPLICATION_ID, ADMIN_USER, userId, duration );
+     }
+ 
+ 
+     /*
+    * (non-Javadoc)
+    * 
+    * @see
+    * org.apache.usergrid.management.ManagementService#revokeAccessTokensForAdminUser
+    * (java.util.UUID)
+    */
+     @Override
+     public void revokeAccessTokensForAdminUser( UUID userId ) throws Exception {
+         revokeTokensForPrincipal( ADMIN_USER, MANAGEMENT_APPLICATION_ID, userId );
+     }
+ 
+ 
+     @Override
+     public void revokeAccessTokenForAdminUser( UUID userId, String token ) throws Exception {
+         if ( anyNull( userId, token ) ) {
+             throw new IllegalArgumentException( "token is required" );
+         }
+ 
+         Entity user = getAdminUserEntityFromAccessToken( token );
+         if ( !user.getUuid().equals( userId ) ) {
+             throw new TokenException( "Could not match token : " + token );
+         }
+ 
+         tokens.revokeToken( token );
+     }
+ 
+ 
+     @Override
+     public Entity getAdminUserEntityFromAccessToken( String token ) throws Exception {
+ 
+         Entity user = getEntityFromAccessToken( token, null, ADMIN_USER );
+         return user;
+     }
+ 
+ 
+     @Override
+     public UserInfo getAdminUserInfoFromAccessToken( String token ) throws Exception {
+         Entity user = getAdminUserEntityFromAccessToken( token );
+         return new UserInfo( MANAGEMENT_APPLICATION_ID, user.getProperties() );
+     }
+ 
+ 
+     @Override
+     public BiMap<UUID, String> getOrganizationsForAdminUser( UUID userId ) throws Exception {
+ 
+         if ( userId == null ) {
+             return null;
+         }
+ 
+         BiMap<UUID, String> organizations = HashBiMap.create();
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Results results = em.getCollection( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "groups", null, 10000,
+                 Level.ALL_PROPERTIES, false );
+ 
+         String path = null;
+ 
+         for ( Entity entity : results.getEntities() ) {
+ 
+             path = ( String ) entity.getProperty( "path" );
+ 
+             if ( path != null ) {
+                 path = path.toLowerCase();
+             }
+ 
+             organizations.put( entity.getUuid(), path );
+         }
+ 
+         return organizations;
+     }
+ 
+ 
+     @Override
+     public Map<String, Object> getAdminUserOrganizationData( UUID userId ) throws Exception {
+         UserInfo user = getAdminUserByUuid( userId );
+         return getAdminUserOrganizationData( user, true );
+     }
+ 
+ 
+     @Override
+     public Long getLastAdminPasswordChange( UUID userId ) throws Exception {
+         CredentialsInfo ci = readUserPasswordCredentials( MANAGEMENT_APPLICATION_ID, userId );
+         return ci.getCreated();
+     }
+ 
+ 
+     @Override
+     public Map<String, Object> getAdminUserOrganizationData( UserInfo user, boolean deep ) throws Exception {
+ 
+         Map<String, Object> json = new HashMap<String, Object>();
+ 
+         json.putAll( JsonUtils.toJsonMap( user ) );
+ 
+         Map<String, Map<String, Object>> jsonOrganizations = new HashMap<String, Map<String, Object>>();
+         json.put( "organizations", jsonOrganizations );
+ 
+         Map<UUID, String> organizations;
+ 
 -        AccountCreationProps.SuperUser superUser = properties.getSuperUser();
 -        if ( superUser.isEnabled() && superUser.getUsername().equals( user.getUsername() ) ) {
++        boolean superuser_enabled = getBooleanProperty( PROPERTIES_SYSADMIN_LOGIN_ALLOWED );
++        String superuser_username = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_NAME );
++        if ( superuser_enabled && ( superuser_username != null ) && superuser_username.equals( user.getUsername() ) ) {
+             organizations = buildOrgBiMap( getOrganizations( null, 10 ) );
+         }
+         else {
+             organizations = getOrganizationsForAdminUser( user.getUuid() );
+         }
+ 
+         for ( Entry<UUID, String> organization : organizations.entrySet() ) {
+             Map<String, Object> jsonOrganization = new HashMap<String, Object>();
+ 
+             jsonOrganizations.put( organization.getValue(), jsonOrganization );
+ 
+             jsonOrganization.put( PROPERTY_NAME, organization.getValue() );
+             jsonOrganization.put( PROPERTY_UUID, organization.getKey() );
+             jsonOrganization.put( "properties", getOrganizationByUuid( organization.getKey() ).getProperties() );
+ 
+             if ( deep ) {
+                 BiMap<UUID, String> applications = getApplicationsForOrganization( organization.getKey() );
+                 jsonOrganization.put( "applications", applications.inverse() );
+ 
+                 List<UserInfo> users = getAdminUsersForOrganization( organization.getKey() );
+                 Map<String, Object> jsonUsers = new HashMap<String, Object>();
+                 for ( UserInfo u : users ) {
+                     jsonUsers.put( u.getUsername(), u );
+                 }
+                 jsonOrganization.put( "users", jsonUsers );
+             }
+         }
+ 
+         return json;
+     }
+ 
+ 
+     @Override
+     public Map<String, Object> getOrganizationData( OrganizationInfo organization ) throws Exception {
+ 
+         Map<String, Object> jsonOrganization = new HashMap<String, Object>();
+         jsonOrganization.putAll( JsonUtils.toJsonMap( organization ) );
+ 
+         BiMap<UUID, String> applications = getApplicationsForOrganization( organization.getUuid() );
+         jsonOrganization.put( "applications", applications.inverse() );
+ 
+         List<UserInfo> users = getAdminUsersForOrganization( organization.getUuid() );
+         Map<String, Object> jsonUsers = new HashMap<String, Object>();
+         for ( UserInfo u : users ) {
+             jsonUsers.put( u.getUsername(), u );
+         }
+         jsonOrganization.put( "users", jsonUsers );
+ 
+         return jsonOrganization;
+     }
+ 
+ 
+     @Override
+     public void addAdminUserToOrganization( UserInfo user, OrganizationInfo organization, boolean email )
+             throws Exception {
+ 
+         if ( ( user == null ) || ( organization == null ) ) {
+             return;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.addToCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organization.getUuid() ), "users",
+                 new SimpleEntityRef( User.ENTITY_TYPE, user.getUuid() ) );
+ 
+         if ( email ) {
+             sendAdminUserInvitedEmail( user, organization );
+         }
+     }
+ 
+ 
+     @Override
+     public void removeAdminUserFromOrganization( UUID userId, UUID organizationId ) throws Exception {
+ 
+         if ( ( userId == null ) || ( organizationId == null ) ) {
+             return;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ 
+         try {
+             if ( em.getCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organizationId ), "users", null, 2,
+                     Level.IDS, false ).size() <= 1 ) {
+                 throw new Exception();
+             }
+         }
+         catch ( Exception e ) {
+             throw new UnableToLeaveOrganizationException( "Organizations must have at least one member." );
+         }
+ 
+         em.removeFromCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organizationId ), "users",
+                 new SimpleEntityRef( User.ENTITY_TYPE, userId ) );
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo createApplication( UUID organizationId, String applicationName ) throws Exception {
+ 
+         return createApplication( organizationId, applicationName, null );
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo createApplication( UUID organizationId, String applicationName,
+                                               Map<String, Object> properties ) throws Exception {
+ 
+         if ( ( organizationId == null ) || ( applicationName == null ) ) {
+             return null;
+         }
+ 
+         if ( properties == null ) {
+             properties = new HashMap<String, Object>();
+         }
+ 
+         OrganizationInfo organizationInfo = getOrganizationByUuid( organizationId );
+ 
+         UUID applicationId = emf.createApplication( organizationInfo.getName(), applicationName, properties );
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         properties.put( "name", buildAppName( applicationName, organizationInfo ) );
+         Entity applicationEntity = em.create( applicationId, APPLICATION_INFO, properties );
+ 
+         writeUserToken( MANAGEMENT_APPLICATION_ID, applicationEntity, encryptionService
+                 .plainTextCredentials( generateOAuthSecretKey( AuthPrincipalType.APPLICATION ), null,
+                         MANAGEMENT_APPLICATION_ID ) );
+         addApplicationToOrganization( organizationId, applicationId );
+ 
+         UserInfo user = null;
+         // if we call this method before the full stack is initialized
+         // we'll get an exception
+         try {
+             user = SubjectUtils.getUser();
+         }
+         catch ( UnavailableSecurityManagerException e ) {
+         }
+         if ( ( user != null ) && user.isAdminUser() ) {
+             postOrganizationActivity( organizationId, user, "create", applicationEntity, "Application", applicationName,
+                     "<a href=\"mailto:" + user.getEmail() + "\">" + user.getName() + " (" + user.getEmail()
+                             + ")</a> created a new application named " + applicationName, null );
+         }
+         return new ApplicationInfo( applicationId, applicationEntity.getName() );
+     }
+ 
+ 
+     @Override
+     public OrganizationInfo getOrganizationForApplication( UUID applicationId ) throws Exception {
+ 
+         if ( applicationId == null ) {
+             return null;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Results r = em.getConnectingEntities( applicationId, "owns", "group", Level.ALL_PROPERTIES );
+         Entity entity = r.getEntity();
+         if ( entity != null ) {
+             return new OrganizationInfo( entity.getUuid(), ( String ) entity.getProperty( "path" ) );
+         }
+ 
+         return null;
+     }
+ 
+ 
+     @Override
+     public BiMap<UUID, String> getApplicationsForOrganization( UUID organizationId ) throws Exception {
+ 
+         if ( organizationId == null ) {
+             return null;
+         }
+         BiMap<UUID, String> applications = HashBiMap.create();
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Results results = em.getConnectedEntities( organizationId, "owns", APPLICATION_INFO, Level.ALL_PROPERTIES );
+         if ( !results.isEmpty() ) {
+ 
+             String entityName = null;
+ 
+             for ( Entity entity : results.getEntities() ) {
+                 entityName = entity.getName();
+ 
+                 if ( entityName != null ) {
+                     entityName = entityName.toLowerCase();
+                 }
+ 
+                 applications.put( entity.getUuid(), entityName );
+             }
+         }
+ 
+         return applications;
+     }
+ 
+ 
+     @Override
+     public BiMap<UUID, String> getApplicationsForOrganizations( Set<UUID> organizationIds ) throws Exception {
+         if ( organizationIds == null ) {
+             return null;
+         }
+         BiMap<UUID, String> applications = HashBiMap.create();
+         for ( UUID organizationId : organizationIds ) {
+             BiMap<UUID, String> organizationApplications = getApplicationsForOrganization( organizationId );
+             applications.putAll( organizationApplications );
+         }
+         return applications;
+     }
+ 
+ 
+     @Override
+     public UUID addApplicationToOrganization( UUID organizationId, UUID applicationId ) throws Exception {
+ 
+         if ( ( organizationId == null ) || ( applicationId == null ) ) {
+             return null;
+         }
+ 
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.createConnection( new SimpleEntityRef( "group", organizationId ), "owns",
+                 new SimpleEntityRef( APPLICATION_INFO, applicationId ) );
+ 
+         return applicationId;
+     }
+ 
+ 
+     @Override
+     public void deleteOrganizationApplication( UUID organizationId, UUID applicationId ) throws Exception {
+         // TODO Auto-generated method stub
+ 
+     }
+ 
+ 
+     @Override
+     public void removeOrganizationApplication( UUID organizationId, UUID applicationId ) throws Exception {
+         // TODO Auto-generated method stub
+ 
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo getApplicationInfo( String applicationName ) throws Exception {
+         if ( applicationName == null ) {
+             return null;
+         }
+         UUID applicationId = emf.lookupApplication( applicationName );
+         if ( applicationId == null ) {
+             return null;
+         }
+         return new ApplicationInfo( applicationId, applicationName.toLowerCase() );
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo getApplicationInfo( UUID applicationId ) throws Exception {
+         if ( applicationId == null ) {
+             return null;
+         }
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         Entity entity = em.get( applicationId );
+ 
+         if ( entity != null ) {
+             return new ApplicationInfo( applicationId, entity.getName() );
+         }
+         return null;
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo getApplicationInfo( Identifier id ) throws Exception {
+         if ( id == null ) {
+             return null;
+         }
+         if ( id.isUUID() ) {
+             return getApplicationInfo( id.getUUID() );
+         }
+         if ( id.isName() ) {
+             return getApplicationInfo( id.getName() );
+         }
+         return null;
+     }
+ 
+ 
+     @Override
+     public ApplicationInfo getApplicationInfoFromAccessToken( String token ) throws Exception {
+         Entity entity = getEntityFromAccessToken( token, null, APPLICATION );
+         if ( entity == null ) {
+             throw new TokenException( "Could not find an entity for that access token: " + token );
+         }
+         return new ApplicationInfo( entity.getProperties() );
+     }
+ 
+ 
+     @Override
+     public ServiceResults getApplicationMetadata( UUID applicationId ) throws Exception {
+ 
+         if ( applicationId == null ) {
+             return ServiceResults.genericServiceResults();
+         }
+ 
+         EntityManager em = emf.getEntityManager( applicationId );
+         Entity entity = em.get( em.getApplicationRef() );
+ 
+         Results r = Results.fromEntity( entity );
+ 
+         Map<String, Object> collections = em.getApplicationCollectionMetadata();
+         if ( collections.size() > 0 ) {
+             r.setMetadata( em.getApplicationRef().getUuid(), "collections", collections );
+         }
+         return genericServiceResults( r );
+     }
+ 
+ 
+     public String getSecret( UUID applicationId, AuthPrincipalType type, UUID id ) throws Exception {
+         if ( AuthPrincipalType.ORGANIZATION.equals( type ) || AuthPrincipalType.APPLICATION.equals( type ) ) {
+             UUID ownerId =
+                     AuthPrincipalType.APPLICATION_USER.equals( type ) ? applicationId : MANAGEMENT_APPLICATION_ID;
+ 
+             return getCredentialsSecret( readUserToken( ownerId, id ) );
+         }
+         else if ( AuthPrincipalType.ADMIN_USER.equals( type ) || AuthPrincipalType.APPLICATION_USER.equals( type ) ) {
+             return getCredentialsSecret( readUserPasswordCredentials( applicationId, id ) );
+         }
+         throw new IllegalArgumentException( "Must specify an admin user, organization or application principal" );
+     }
+ 
+ 
+     @Override
+     public String getClientIdForOrganization( UUID organizationId ) {
+         return ClientCredentialsInfo.getClientIdForTypeAndUuid( AuthPrincipalType.ORGANIZATION, organizationId );
+     }
+ 
+ 
+     @Override
+     public String getClientSecretForOrganization( UUID organizationId ) throws Exception {
+         return getSecret( MANAGEMENT_APPLICATION_ID, AuthPrincipalType.ORGANIZATION, organizationId );
+     }
+ 
+ 
+     @Override
+     public String getClientIdForApplication( UUID applicationId ) {
+         return ClientCredentialsInfo.getClientIdForTypeAndUuid( AuthPrincipalType.APPLICATION, applicationId );
+     }
+ 
+ 
+     @Override
+     public String getClientSecretForApplication( UUID applicationId ) throws Exception {
+         return getSecret( MANAGEMENT_APPLICATION_ID, AuthPrincipalType.APPLICATION, applicationId );
+     }
+ 
+ 
+     public String newSecretKey( AuthPrincipalType type, UUID id ) throws Exception {
+         String secret = generateOAuthSecretKey( type );
+ 
+         writeUserToken( MANAGEMENT_APPLICATION_ID, new SimpleEntityRef( type.getEntityType(), id ),
+                 encryptionService.plainTextCredentials( secret, id, MANAGEMENT_APPLICATION_ID ) );
+ 
+         return secret;
+     }
+ 
+ 
+     @Override
+     public String newClientSecretForOrganization( UUID organizationId ) throws Exception {
+         return newSecretKey( AuthPrincipalType.ORGANIZATION, organizationId );
+     }
+ 
+ 
+     @Override
+     public String newClientSecretForApplication( UUID applicationId ) throws Exception {
+         return newSecretKey( AuthPrincipalType.APPLICATION, applicationId );
+     }
+ 
+ 
+     @Override
+     public AccessInfo authorizeClient( String clientId, String clientSecret, long ttl ) throws Exception {
+         if ( ( clientId == null ) || ( clientSecret == null ) ) {
+             return null;
+         }
+         UUID uuid = getUUIDFromClientId( clientId );
+         if ( uuid == null ) {
+             return null;
+         }
+         AuthPrincipalType type = getTypeFromClientId( clientId );
+         if ( type == null ) {
+             return null;
+         }
+         AccessInfo access_info = null;
+         if ( clientSecret.equals( getSecret( MANAGEMENT_APPLICATION_ID, type, uuid ) ) ) {
+ 
+             String token = getTokenForPrincipal( ACCESS, null, MANAGEMENT_APPLICATION_ID, type, uuid, ttl );
+ 
+             long duration = tokens.getMaxTokenAgeInSeconds( token );
+ 
+             access_info = new AccessInfo().withExpiresIn( duration ).withAccessToken( token );
+ 
+             if ( type.equals( AuthPrincipalType.APPLICATION ) ) {
+                 ApplicationInfo app = getApplicationInfo( uuid );
+                 access_info = access_info.withProperty( "application", app.getId() );
+             }
+             else if ( type.equals( AuthPrincipalType.ORGANIZATION ) ) {
+                 OrganizationInfo organization = getOrganizationByUuid( uuid );
+                 access_info = access_info.withProperty( "organization", getOrganizationData( organization ) );
+             }
+         }
+         return access_info;
+     }
+ 
+ 
+     @Override
+     public PrincipalCredentialsToken getPrincipalCredentialsTokenForClientCredentials( String clientId,
+                                                                                        String clientSecret )
+             throws Exception {
+         if ( ( clientId == null ) || ( clientSecret == null ) ) {
+             return null;
+         }
+         UUID uuid = getUUIDFromClientId( clientId );
+         if ( uuid == null ) {
+             return null;
+         }
+         AuthPrincipalType type = getTypeFromClientId( clientId );
+         if ( type == null ) {
+             return null;
+         }
+         PrincipalCredentialsToken token = null;
+         if ( clientSecret.equals( getSecret( MANAGEMENT_APPLICATION_ID, type, uuid ) ) ) {
+             if ( type.equals( AuthPrincipalType.APPLICATION ) ) {
+                 ApplicationInfo app = getApplicationInfo( uuid );
+                 token = new PrincipalCredentialsToken( new ApplicationPrincipal( app ),
+                         new ApplicationClientCredentials( clientId, clientSecret ) );
+             }
+             else if ( type.equals( AuthPrincipalType.ORGANIZATION ) ) {
+                 OrganizationInfo organization = getOrganizationByUuid( uuid );
+                 token = new PrincipalCredentialsToken( new OrganizationPrincipal( organization ),
+                         new OrganizationClientCredentials( clientId, clientSecret ) );
+             }
+         }
+         return token;
+     }
+ 
+ 
+     public AccessInfo authorizeAppUser( String clientType, String clientId, String clientSecret ) throws Exception {
+ 
+         return null;
+     }
+ 
+ 
+     @Override
+     public String getPasswordResetTokenForAdminUser( UUID userId, long ttl ) throws Exception {
+         return getTokenForPrincipal( EMAIL, TOKEN_TYPE_PASSWORD_RESET, MANAGEMENT_APPLICATION_ID, ADMIN_USER, userId,
+                 ttl );
+     }
+ 
+ 
+     @Override
+     public boolean checkPasswordResetTokenForAdminUser( UUID userId, String token ) throws Exception {
+         AuthPrincipalInfo principal = null;
+         try {
+             principal = getPrincipalFromAccessToken( token, TOKEN_TYPE_PASSWORD_RESET, ADMIN_USER );
+         }
+         catch ( Exception e ) {
+             logger.error( "Unable to verify token", e );
+         }
+         return ( principal != null ) && userId.equals( principal.getUuid() );
+     }
+ 
+ 
+     @Override
+     public String getActivationTokenForAdminUser( UUID userId, long ttl ) throws Exception {
+         return getTokenForPrincipal( EMAIL, TOKEN_TYPE_ACTIVATION, MANAGEMENT_APPLICATION_ID, ADMIN_USER, userId, ttl );
+     }
+ 
+ 
+     @Override
+     public String getConfirmationTokenForAdminUser( UUID userId, long ttl ) throws Exception {
+         return getTokenForPrincipal( EMAIL, TOKEN_TYPE_CONFIRM, MANAGEMENT_APPLICATION_ID, ADMIN_USER, userId, ttl );
+     }
+ 
+ 
+     @Override
+     public void activateAdminUser( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.setProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "activated", true );
+     }
+ 
+ 
+     @Override
+     public User deactivateUser( UUID applicationId, UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( applicationId );
+ 
+         User user = em.get( userId, User.class );
+ 
+         if ( user == null ) {
+             throw new ManagementException(
+                     String.format( "User with id %s does not exist in app %s", userId, applicationId ) );
+         }
+ 
+         user.setActivated( false );
+         user.setDeactivated( System.currentTimeMillis() );
+ 
+         em.update( user );
+ 
+         // revoke all access tokens for the app
+         revokeAccessTokensForAppUser( applicationId, userId );
+ 
+         return user;
+     }
+ 
+ 
+     @Override
+     public boolean isAdminUserActivated( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         return Boolean.TRUE.equals( em.getProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "activated" ) );
+     }
+ 
+ 
+     @Override
+     public void confirmAdminUser( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.setProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "confirmed", true );
+     }
+ 
+ 
+     @Override
+     public void unconfirmAdminUser( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.setProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "confirmed", false );
+     }
+ 
+ 
+     @Override
+     public boolean isAdminUserConfirmed( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         return Boolean.TRUE.equals( em.getProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "confirmed" ) );
+     }
+ 
+ 
+     @Override
+     public void enableAdminUser( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.setProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "disabled", false );
+     }
+ 
+ 
+     @Override
+     public void disableAdminUser( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         em.setProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "disabled", true );
+ 
+         revokeAccessTokensForAdminUser( userId );
+     }
+ 
+ 
+     @Override
+     public boolean isAdminUserEnabled( UUID userId ) throws Exception {
+         EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+         return !Boolean.TRUE.equals( em.getProperty( new SimpleEntityRef( User.ENTITY_TYPE, userId ), "disabled" ) );
+     }
+ 
+ 
+     privat

<TRUNCATED>

Mime
View raw message