[PATCH conductor] Redmine #3345: Initial user groups implementation

Scott Seago sseago at redhat.com
Mon Jun 4 15:56:32 UTC 2012


https://www.aeolusproject.org/redmine/issues/3345

This includes models for user groups, refactoring necessary for linking
permissions to groups, and updated permissions checks.

Not yet included is UI to manage groups, or LDAP group integration.
---
 src/app/controllers/application_controller.rb      |   32 ++++++--
 src/app/controllers/catalogs_controller.rb         |   22 +++--
 src/app/controllers/deployables_controller.rb      |   16 +++-
 src/app/controllers/deployments_controller.rb      |   36 ++++++---
 .../controllers/hardware_profiles_controller.rb    |   23 +++++-
 src/app/controllers/images_controller.rb           |    3 +-
 src/app/controllers/instances_controller.rb        |   32 +++++---
 src/app/controllers/logs_controller.rb             |   10 ++-
 src/app/controllers/permissions_controller.rb      |   30 ++++----
 src/app/controllers/pool_families_controller.rb    |   11 ++-
 src/app/controllers/pools_controller.rb            |   83 +++++++++++++-------
 .../controllers/provider_accounts_controller.rb    |    6 +-
 src/app/controllers/providers_controller.rb        |   11 ++-
 src/app/controllers/realm_mappings_controller.rb   |    5 +-
 src/app/controllers/realms_controller.rb           |    6 +-
 src/app/helpers/mustache_helper.rb                 |   10 ++-
 src/app/models/deployment.rb                       |   16 ++--
 src/app/models/derived_permission.rb               |    6 +-
 src/app/models/entity.rb                           |   29 +++++++
 src/app/models/instance.rb                         |    4 +-
 src/app/models/permission.rb                       |   21 ++++--
 src/app/models/permissioned_object.rb              |   40 +++++++---
 src/app/models/pool.rb                             |    4 +-
 src/app/models/session_entity.rb                   |   47 +++++++++++
 src/app/models/user.rb                             |   15 +++-
 src/app/models/user_group.rb                       |   45 +++++++++++
 src/app/services/application_service.rb            |    2 +-
 src/app/services/registration_service.rb           |    2 +-
 src/app/views/permissions/_form.html.haml          |   10 +--
 src/app/views/permissions/_permissions.html.haml   |    6 +-
 src/app/views/pools/_pretty_list.html.haml         |    2 +-
 src/config/initializers/session.rb                 |   23 ++++++
 src/config/initializers/warden.rb                  |    2 +-
 src/config/locales/en.yml                          |    1 +
 src/db/migrate/20110207101100_deployment_roles.rb  |   80 -------------------
 .../migrate/20111122203000_add_deployable_roles.rb |   82 -------------------
 .../migrate/20120514121500_create_user_groups.rb   |   37 +++++++++
 src/db/migrate/20120514131500_create_entities.rb   |   38 +++++++++
 .../20120517131500_create_session_entities.rb      |   32 ++++++++
 .../20120520151500_change_permission_user.rb       |   79 +++++++++++++++++++
 src/features/step_definitions/authentication.rb    |    9 +-
 src/features/step_definitions/permission_steps.rb  |    8 +-
 src/features/step_definitions/pool_family_steps.rb |    2 +-
 src/features/step_definitions/pool_steps.rb        |    2 +-
 src/lib/tasks/dc_tasks.rake                        |    2 +-
 .../controllers/config_servers_controller_spec.rb  |    4 +-
 .../controllers/permissions_controller_spec.rb     |    2 +-
 .../provider_accounts_controller_spec.rb           |    2 +-
 src/spec/factories/permission.rb                   |   16 ++--
 src/spec/factories/session.rb                      |   24 ++++++
 src/spec/models/deployable_spec.rb                 |    4 +-
 src/spec/models/deployment_spec.rb                 |   22 +++--
 src/spec/models/derived_permission_spec.rb         |   50 ++++++++++++
 src/spec/models/permission_spec.rb                 |   28 +++++--
 src/spec/services/registration_service_spec.rb     |    4 +-
 src/spec/spec_helper.rb                            |    5 +
 56 files changed, 776 insertions(+), 367 deletions(-)
 create mode 100644 src/app/models/entity.rb
 create mode 100644 src/app/models/session_entity.rb
 create mode 100644 src/app/models/user_group.rb
 create mode 100644 src/config/initializers/session.rb
 delete mode 100644 src/db/migrate/20110207101100_deployment_roles.rb
 delete mode 100644 src/db/migrate/20111122203000_add_deployable_roles.rb
 create mode 100644 src/db/migrate/20120514121500_create_user_groups.rb
 create mode 100644 src/db/migrate/20120514131500_create_entities.rb
 create mode 100644 src/db/migrate/20120517131500_create_session_entities.rb
 create mode 100644 src/db/migrate/20120520151500_change_permission_user.rb
 create mode 100644 src/spec/factories/session.rb
 create mode 100644 src/spec/models/derived_permission_spec.rb

diff --git a/src/app/controllers/application_controller.rb b/src/app/controllers/application_controller.rb
index fda6a06..6f280be 100644
--- a/src/app/controllers/application_controller.rb
+++ b/src/app/controllers/application_controller.rb
@@ -24,7 +24,7 @@ require 'will_paginate/array'
 class ApplicationController < ActionController::Base
   # FIXME: not sure what we're doing aobut service layer w/ deltacloud
   include ApplicationService
-  helper_method :current_user, :filter_view?
+  helper_method :current_session, :current_user, :filter_view?
   before_filter :read_breadcrumbs, :set_locale
 
   # General error handlers, must be in order from least specific
@@ -99,8 +99,10 @@ class ApplicationController < ActionController::Base
 
   def get_nav_items
     if current_user.present?
-      @providers = Provider.list_for_user(current_user, Privilege::VIEW)
-      @pools = Pool.list_for_user(current_user, Privilege::VIEW)
+      @providers = Provider.list_for_user(current_session, current_user,
+                                          Privilege::VIEW)
+      @pools = Pool.list_for_user(current_session, current_user,
+                                  Privilege::VIEW)
     end
   end
 
@@ -177,6 +179,9 @@ class ApplicationController < ActionController::Base
   def http_auth_user
     return unless request.authorization && request.authorization =~ /^Basic (.*)/m
     authenticate!(:scope => :api)
+    request.session_options = request.session_options.dup
+    request.session_options[:expire_after] = 2.minutes
+    request.session_options.freeze
     # we use :api scope for authentication to avoid saving session.
     # But it's handy to set authenticated user in default scope, so we
     # can use current_user, instead of current_user(:api)
@@ -184,6 +189,21 @@ class ApplicationController < ActionController::Base
     return user(:api)
   end
 
+  def current_session
+    @current_session ||= ActiveRecord::SessionStore::Session.
+      find_by_session_id(request.session_options[:id])
+    # FIXME: I shouldn't have to reload sessions here, but for some reason
+    # without reloading it wasn't working for non-admin permissions.
+    # If we ever need to add session_entities for _other_ users to the
+    # current session, this won't work
+    if @current_session and (!@current_session.session_entities.any? or
+                             @current_session.session_entities.first.user != current_user)
+      SessionEntity.update_session(@current_session, current_user)
+      @current_session.reload
+    end
+    @current_session
+  end
+
   def require_user
     return if current_user or http_auth_user
     respond_to do |format|
@@ -309,7 +329,7 @@ class ApplicationController < ActionController::Base
     if "permissions" == params[:details_tab]
       require_privilege(Privilege::PERM_VIEW, perm_obj)
     end
-    if perm_obj.has_privilege(current_user, Privilege::PERM_VIEW)
+    if perm_obj.has_privilege(current_session, current_user, Privilege::PERM_VIEW)
       @roles = Role.find_all_by_scope(@permission_object.class.name)
       if @tabs
         @tabs << {:name => t('role_assignments'),
@@ -343,9 +363,7 @@ class ApplicationController < ActionController::Base
         { :name => 'checkbox', :class => 'checkbox', :sortable => false }
     end
     @permission_list_header += [
-      { :name => t('users.index.username') },
-      { :name => t('users.index.last_name'), :sortable => false },
-      { :name => t('users.index.first_name'), :sortable => false },
+      { :name => t('permissions.name')},
       { :name => t("role"), :sort_attr => :role},
     ]
     if @show_inherited
diff --git a/src/app/controllers/catalogs_controller.rb b/src/app/controllers/catalogs_controller.rb
index 270546d..e928988 100644
--- a/src/app/controllers/catalogs_controller.rb
+++ b/src/app/controllers/catalogs_controller.rb
@@ -20,8 +20,12 @@ class CatalogsController < ApplicationController
   def index
     @title = t('catalogs.catalogs')
     clear_breadcrumbs
-    @catalogs = Catalog.apply_filters(:preset_filter_id => params[:catalogs_preset_filter], :search_filter => params[:catalogs_search]).list_for_user(current_user, Privilege::VIEW)
-    @can_create = Pool.list_for_user(current_user, Privilege::CREATE, Catalog).present?
+    @catalogs = Catalog.
+      apply_filters(:preset_filter_id => params[:catalogs_preset_filter],
+                    :search_filter => params[:catalogs_search]).
+      list_for_user(current_session, current_user, Privilege::VIEW)
+    @can_create = Pool.list_for_user(current_session, current_user,
+                                     Privilege::CREATE, Catalog).present?
     save_breadcrumb(catalogs_path(:viewstate => @viewstate ? @viewstate.id : nil))
     set_header
     set_admin_content_tabs 'catalogs'
@@ -42,9 +46,9 @@ class CatalogsController < ApplicationController
     @catalog = Catalog.find(params[:id])
     @title = @catalog.name
     @deployables = @catalog.deployables.
-                            list_for_user(current_user, Privilege::VIEW).
-                            apply_filters(:preset_filter_id => params[:deployables_preset_filter],
-                                          :search_filter => params[:deployables_search])
+      list_for_user(current_session, current_user, Privilege::VIEW).
+      apply_filters(:preset_filter_id => params[:deployables_preset_filter],
+                    :search_filter => params[:deployables_search])
     require_privilege(Privilege::VIEW, @catalog)
     save_breadcrumb(catalog_path(@catalog), @catalog.name)
     @header = [
@@ -143,12 +147,12 @@ class CatalogsController < ApplicationController
 
   def load_pools
     if @catalog.pool_family
-      @pools = @catalog.pool_family.pools.list_for_user(current_user,
-                                                        Privilege::CREATE,
-                                                        Catalog)
+      @pools = @catalog.pool_family.pools.
+        list_for_user(current_session, current_user, Privilege::CREATE, Catalog)
       @pools.unshift(@catalog.pool) unless @pools.include?(@catalog.pool)
     else
-      @pools = Pool.list_for_user(current_user, Privilege::CREATE, Catalog)
+      @pools = Pool.list_for_user(current_session, current_user,
+                                  Privilege::CREATE, Catalog)
     end
   end
 end
diff --git a/src/app/controllers/deployables_controller.rb b/src/app/controllers/deployables_controller.rb
index 1fb8fba..3e3b76a 100644
--- a/src/app/controllers/deployables_controller.rb
+++ b/src/app/controllers/deployables_controller.rb
@@ -27,7 +27,8 @@ class DeployablesController < ApplicationController
       @catalog_entries = @deployables.collect { |d| d.catalog_entries.first }
     else
       save_breadcrumb(deployables_path)
-      @deployables = Deployable.without_catalog.list_for_user(current_user, Privilege::VIEW)
+      @deployables = Deployable.without_catalog.
+        list_for_user(current_session, current_user, Privilege::VIEW)
     end
     set_header
   end
@@ -36,7 +37,8 @@ class DeployablesController < ApplicationController
     @deployable = Deployable.new(params[:deployable])
     if params[:create_from_image]
       @image = Aeolus::Image::Warehouse::Image.find(params[:create_from_image])
-      @hw_profiles = HardwareProfile.frontend.list_for_user(current_user, Privilege::VIEW)
+      @hw_profiles = HardwareProfile.frontend.
+        list_for_user(current_session, current_user, Privilege::VIEW)
       @deployable.name = @image.name
       @selected_catalogs = Array(params[:catalog_id])
       load_catalogs
@@ -65,7 +67,8 @@ class DeployablesController < ApplicationController
     require_privilege(Privilege::VIEW, @deployable)
     save_breadcrumb(polymorphic_path([@catalog, @deployable]), @deployable.name)
     @providers = Provider.all
-    @catalogs_options = Catalog.list_for_user(current_user, Privilege::VIEW).select do |c|
+    @catalogs_options = Catalog.list_for_user(current_session, current_user,
+                                              Privilege::VIEW).select do |c|
       !@deployable.catalogs.include?(c) and
         @deployable.catalogs.first.pool_family == c.pool_family
     end
@@ -179,7 +182,8 @@ class DeployablesController < ApplicationController
       if params[:create_from_image].present?
         @image = Aeolus::Image::Warehouse::Image.find(params[:create_from_image])
         load_catalogs
-        @hw_profiles = HardwareProfile.frontend.list_for_user(current_user, Privilege::VIEW)
+        @hw_profiles = HardwareProfile.frontend.
+          list_for_user(current_session, current_user, Privilege::VIEW)
       else
         @catalog = @selected_catalogs.first
         params.delete(:edit_xml) if params[:edit_xml]
@@ -292,7 +296,9 @@ class DeployablesController < ApplicationController
 
   def load_catalogs
     @pool_family = PoolFamily.where(:name => @image.environment).first
-    @catalogs = Catalog.list_for_user(current_user, Privilege::CREATE, Deployable).where('pool_family_id' => @pool_family.id)
+    @catalogs = Catalog.list_for_user(current_session, current_user,
+                                      Privilege::CREATE, Deployable).
+      where('pool_family_id' => @pool_family.id)
   end
 
   def import_xml_from_url(url)
diff --git a/src/app/controllers/deployments_controller.rb b/src/app/controllers/deployments_controller.rb
index bb7f22f..77b7cb8 100644
--- a/src/app/controllers/deployments_controller.rb
+++ b/src/app/controllers/deployments_controller.rb
@@ -81,7 +81,8 @@ class DeploymentsController < ApplicationController
 
     if @services.empty? or @services.all? {|s, a| s.parameters.empty?}
       # we can skip the launch-time parameters screen
-      @errors = @deployment.check_assemblies_matches(current_user)
+      @errors = @deployment.check_assemblies_matches(current_session,
+                                                     current_user)
       set_errors_flash(@errors)
       @additional_quota = count_additional_quota(@deployment)
       render 'overview' and return
@@ -109,7 +110,8 @@ class DeploymentsController < ApplicationController
 
     respond_to do |format|
       if @deployable.xml && @deployment.valid_deployable_xml?(@deployable.xml) && d_errors.empty?
-        @errors = @deployment.check_assemblies_matches(current_user)
+        @errors = @deployment.check_assemblies_matches(current_session,
+                                                       current_user)
         set_errors_flash(@errors)
         @additional_quota = count_additional_quota(@deployment)
 
@@ -149,7 +151,7 @@ class DeploymentsController < ApplicationController
     return unless check_deployable_images
 
     respond_to do |format|
-      if @deployment.create_and_launch(current_user)
+      if @deployment.create_and_launch(current_session, current_user)
         format.html do
           flash[:notice] = t "deployments.flash.notice.launched"
           redirect_to deployment_path(@deployment)
@@ -343,7 +345,9 @@ class DeploymentsController < ApplicationController
 
   def launch_from_catalog
     @catalog = Catalog.find(params[:catalog_id])
-    @deployables = @catalog.deployables.list_for_user(current_user, Privilege::VIEW).paginate(:page => params[:page] || 1, :per_page => 6)
+    @deployables = @catalog.deployables.
+      list_for_user(current_session, current_user, Privilege::VIEW).
+      paginate(:page => params[:page] || 1, :per_page => 6)
     require_privilege(Privilege::VIEW, @catalog)
   end
 
@@ -379,13 +383,16 @@ class DeploymentsController < ApplicationController
       { :name => t("pools.index.owner"), :sortable => false },
       { :name => t("providers.provider"), :sortable => false }
     ]
-    @pools = Pool.list_for_user(current_user, Privilege::CREATE, Deployment)
-    @deployments = paginate_collection(Deployment.includes(:owner, :pool, :instances).
-                                                  apply_filters(:preset_filter_id => params[:deployments_preset_filter], :search_filter => params[:deployments_search]).
-                                                  list_for_user(current_user, Privilege::VIEW).
-                                                  where('deployments.pool_id' => @pools).
-                                                  order(sort_column(Deployment, "deployments.name") +' '+ sort_direction),
-                                       params[:page], PER_PAGE)
+    @pools = Pool.list_for_user(current_session, current_user,
+                                Privilege::CREATE, Deployment)
+    @deployments = paginate_collection(
+      Deployment.includes(:owner, :pool, :instances).
+        apply_filters(:preset_filter_id => params[:deployments_preset_filter],
+                      :search_filter => params[:deployments_search]).
+        list_for_user(current_session, current_user, Privilege::VIEW).
+        where('deployments.pool_id' => @pools).
+        order(sort_column(Deployment, "deployments.name") +' '+ sort_direction),
+      params[:page], PER_PAGE)
   end
 
   def count_additional_quota(deployment)
@@ -407,8 +414,11 @@ class DeploymentsController < ApplicationController
   end
 
   def init_new_deployment_attrs
-    @deployables = Deployable.includes({:catalogs => :pool}).list_for_user(current_user, Privilege::USE).select{|d| d.catalogs.collect{|c| c.pool}.include?(@pool)}
-    @pools = Pool.list_for_user(current_user, Privilege::CREATE, Deployment)
+    @deployables = Deployable.includes({:catalogs => :pool}).
+      list_for_user(current_session, current_user, Privilege::USE).
+      select{|d| d.catalogs.collect{|c| c.pool}.include?(@pool)}
+    @pools = Pool.list_for_user(current_session, current_user,
+                                Privilege::CREATE, Deployment)
     @deployable = params[:deployable_id] ? Deployable.find(params[:deployable_id]) : nil
     @realms = FrontendRealm.all
     @hardware_profiles = HardwareProfile.all(
diff --git a/src/app/controllers/hardware_profiles_controller.rb b/src/app/controllers/hardware_profiles_controller.rb
index dc19c13..2b91d5d 100644
--- a/src/app/controllers/hardware_profiles_controller.rb
+++ b/src/app/controllers/hardware_profiles_controller.rb
@@ -233,13 +233,28 @@ class HardwareProfilesController < ApplicationController
     sort_order = sort_direction
     sort_field = sort_column(HardwareProfile, 'name')
     if sort_field == "name"
-      @hardware_profiles = HardwareProfile.where('provider_id IS NULL', {}).apply_filters(:preset_filter_id => params[:hardware_profiles_preset_filter], :search_filter => params[:hardware_profiles_search]).list_for_user(current_user, Privilege::VIEW).order("hardware_profiles.name #{sort_direction}")
+      @hardware_profiles = HardwareProfile.where('provider_id IS NULL', {}).
+        apply_filters(:preset_filter_id =>
+                        params[:hardware_profiles_preset_filter],
+                      :search_filter => params[:hardware_profiles_search]).
+        list_for_user(current_session, current_user, Privilege::VIEW).
+        order("hardware_profiles.name #{sort_direction}")
     else
-      @hardware_profiles = HardwareProfile.where('provider_id IS NULL', {}).apply_filters(:preset_filter_id => params[:hardware_profiles_preset_filter], :search_filter => params[:hardware_profiles_search]).list_for_user(current_user, Privilege::VIEW)
+      @hardware_profiles = HardwareProfile.where('provider_id IS NULL', {}).
+        apply_filters(:preset_filter_id =>
+                        params[:hardware_profiles_preset_filter],
+                      :search_filter => params[:hardware_profiles_search]).
+        list_for_user(current_session, current_user, Privilege::VIEW)
       if sort_order == "asc"
-        @hardware_profiles.sort! {|x,y| x.get_property_map[sort_field].sort_value(true) <=> y.get_property_map[sort_field].sort_value(true)}
+        @hardware_profiles.sort! do |x,y|
+          x.get_property_map[sort_field].sort_value(true) <=>
+            y.get_property_map[sort_field].sort_value(true)
+        end
       else
-        @hardware_profiles.sort! {|x,y| y.get_property_map[sort_field].sort_value(false) <=> x.get_property_map[sort_field].sort_value(false)}
+        @hardware_profiles.sort! do |x,y|
+          y.get_property_map[sort_field].sort_value(false) <=>
+            x.get_property_map[sort_field].sort_value(false)
+        end
       end
     end
   end
diff --git a/src/app/controllers/images_controller.rb b/src/app/controllers/images_controller.rb
index a114f9d..5fb2143 100644
--- a/src/app/controllers/images_controller.rb
+++ b/src/app/controllers/images_controller.rb
@@ -166,7 +166,8 @@ class ImagesController < ApplicationController
   def new
     @environment = PoolFamily.find(params[:environment])
     check_permissions
-    @accounts = @environment.provider_accounts.enabled.list_for_user(current_user, Privilege::USE)
+    @accounts = @environment.provider_accounts.enabled.
+      list_for_user(current_session, current_user, Privilege::USE)
     if @accounts.empty?
       flash.now[:error] = params[:tab] == 'import' ?
         t("images.flash.error.no_provider_accounts_for_import") :
diff --git a/src/app/controllers/instances_controller.rb b/src/app/controllers/instances_controller.rb
index 85a5235..ac78096 100644
--- a/src/app/controllers/instances_controller.rb
+++ b/src/app/controllers/instances_controller.rb
@@ -228,7 +228,9 @@ class InstancesController < ApplicationController
   end
 
   def init_new_instance_attrs
-    @pools = Pool.list_for_user(current_user, Privilege::CREATE, Instance).where(:enabled => true)
+    @pools = Pool.list_for_user(current_session, current_user,
+                                Privilege::CREATE, Instance).
+      where(:enabled => true)
     @realms = FrontendRealm.all
     @hardware_profiles = HardwareProfile.all(
       :include => :architecture,
@@ -248,20 +250,30 @@ class InstancesController < ApplicationController
       {:name => t('instances.headers.created_by'), :sort_attr => 'users.last_name'},
     ]
 
-    @pools = Pool.list_for_user(current_user, Privilege::CREATE, Instance)
+    @pools = Pool.list_for_user(current_session, current_user,
+                                Privilege::CREATE, Instance)
   end
 
   def load_instances
     if params[:deployment_id].blank?
-      @instances = paginate_collection(Instance.includes(:owner).apply_filters(:preset_filter_id => params[:instances_preset_filter], :search_filter => params[:instances_search]).
-                                                list_for_user(current_user, Privilege::VIEW).list(sort_column(Instance), sort_direction).
-                                                where("instances.pool_id" => @pools),
-                                       params[:page], PER_PAGE)
+      @instances = paginate_collection(
+        Instance.includes(:owner).
+          apply_filters(:preset_filter_id => params[:instances_preset_filter],
+                        :search_filter => params[:instances_search]).
+          list_for_user(current_session, current_user, Privilege::VIEW).
+          list(sort_column(Instance), sort_direction).
+          where("instances.pool_id" => @pools),
+        params[:page], PER_PAGE)
     else
-      @instances = paginate_collection(Instance.includes(:owner).apply_filters(:preset_filter_id => params[:instances_preset_filter], :search_filter => params[:instances_search]).
-                                                list(sort_column(Instance), sort_direction).list_for_user(current_user, Privilege::VIEW).
-                                                where("instances.pool_id" => @pools, "instances.deployment_id" => params[:deployment_id]),
-                                       params[:page], PER_PAGE)
+      @instances = paginate_collection(
+        Instance.includes(:owner).
+          apply_filters(:preset_filter_id => params[:instances_preset_filter],
+                        :search_filter => params[:instances_search]).
+          list(sort_column(Instance), sort_direction).
+          list_for_user(current_session, current_user, Privilege::VIEW).
+          where("instances.pool_id" => @pools,
+                "instances.deployment_id" => params[:deployment_id]),
+        params[:page], PER_PAGE)
     end
   end
 
diff --git a/src/app/controllers/logs_controller.rb b/src/app/controllers/logs_controller.rb
index 8b9e5c4..6f0cab4 100644
--- a/src/app/controllers/logs_controller.rb
+++ b/src/app/controllers/logs_controller.rb
@@ -57,9 +57,11 @@ class LogsController < ApplicationController
                                   {:source => [:pool_family, :pool, :owner]},
                                   :conditions => conditions
                                   )
-    deployments = Deployment.unscoped.list_for_user(current_user,
+    deployments = Deployment.unscoped.list_for_user(current_session,
+                                                    current_user,
                                                     Privilege::VIEW)
-    instances = Instance.unscoped.list_for_user(current_user, Privilege::VIEW)
+    instances = Instance.unscoped.list_for_user(current_session,
+                                                current_user, Privilege::VIEW)
 
     pool_option, pool_option_id = @pool_select.split(":")
     provider_option, provider_option_id = @provider_select.split(":")
@@ -110,7 +112,7 @@ class LogsController < ApplicationController
     @state_options = ([[t('logs.options.default_states'), ""]] +
                       Deployment::STATES + Instance::STATES).uniq
     @pool_options = [[t('logs.options.default_pools'), ""]]
-    PoolFamily.list_for_user(current_user, Privilege::VIEW).
+    PoolFamily.list_for_user(current_session, current_user, Privilege::VIEW).
       find(:all, :include => :pools, :order => "name",
            :select => ["id", "name"]).each do |pool_family|
       @pool_options << [pool_family.name, "pool_family:" + pool_family.id.to_s]
@@ -118,7 +120,7 @@ class LogsController < ApplicationController
         map{|x| [" -- " + x.name, "pool:" + x.id.to_s]}
     end
     @provider_options = [[t('logs.options.default_providers'), ""]]
-    Provider.list_for_user(current_user, Privilege::VIEW).
+    Provider.list_for_user(current_session, current_user, Privilege::VIEW).
       find(:all, :include => :provider_accounts, :order => "name",
            :select => ["id", "name"]).each do |provider|
       @provider_options << [provider.name, "provider:" + provider.id.to_s]
diff --git a/src/app/controllers/permissions_controller.rb b/src/app/controllers/permissions_controller.rb
index 9f984fa..acdbb2c 100644
--- a/src/app/controllers/permissions_controller.rb
+++ b/src/app/controllers/permissions_controller.rb
@@ -40,7 +40,7 @@ class PermissionsController < ApplicationController
       @summary_text = t('permissions.new.choose_roles') + " " + @permission_object.class.model_name.human
     end
     load_headers
-    load_users
+    load_entities
     respond_to do |format|
       format.html
       format.js { render :partial => 'new' }
@@ -51,17 +51,17 @@ class PermissionsController < ApplicationController
     set_permission_object
     added=[]
     not_added=[]
-    params[:user_role_selected].each do |user_role|
-      user_id,role_id = user_role.split(",")
+    params[:entity_role_selected].each do |entity_role|
+      entity_id,role_id = entity_role.split(",")
       unless role_id.nil?
-        permission = Permission.new(:user_id => user_id,
+        permission = Permission.new(:entity_id => entity_id,
                                     :role_id => role_id,
                                     :permission_object => @permission_object)
         if permission.save
-          added << t('permissions.flash.fragment.user_and_role', :user => permission.user.login,
+          added << t('permissions.flash.fragment.user_and_role', :user => permission.entity.name,
                       :role => t(permission.role.name, :scope=> :role_defs, :default => permission.role.name))
         else
-          not_added << t('permissions.flash.fragment.user_and_role', :user => permission.user.login,
+          not_added << t('permissions.flash.fragment.user_and_role', :user => permission.entity.name,
                           :role => t(permission.role.name, :scope=> :role_defs, :default => permission.role.name) )
         end
       end
@@ -96,11 +96,11 @@ class PermissionsController < ApplicationController
         unless permission.role == role
           permission.role = role
           if permission.save
-            modified << t('permissions.flash.fragment.user_and_role_change', :user => permission.user.login,
+            modified << t('permissions.flash.fragment.user_and_role_change', :user => permission.entity.name,
                             :old_role => t(old_role.name, :scope=> :role_defs, :default => old_role.name),
                             :role => t(permission.role.name, :scope=> :role_defs, :default => permission.role.name))
           else
-            not_modified << t('permissions.flash.fragment.user_and_role_change', :user => permission.user.login,
+            not_modified << t('permissions.flash.fragment.user_and_role_change', :user => permission.entity.name,
                             :old_role => t(old_role.name, :scope=> :role_defs, :default => old_role.name) ,
                             :role => t(permission.role.name, :scope=> :role_defs, :default => permission.role.name))
           end
@@ -131,10 +131,10 @@ class PermissionsController < ApplicationController
 
     Permission.find(params[:permission_selected]).each do |p|
       if check_privilege(Privilege::PERM_SET, p.permission_object) && p.destroy
-        deleted << t('permissions.flash.fragment.user_and_role', :user => p.user.login,
+        deleted << t('permissions.flash.fragment.user_and_role', :user => p.entity.name,
                       :role => t(p.role.name, :scope=> :role_defs, :default => p.role.name))
       else
-        not_deleted << t('permissions.flash.fragment.user_and_role', :user => p.user.login,
+        not_deleted << t('permissions.flash.fragment.user_and_role', :user => p.entity.name,
                       :role => t(p.role.name, :scope=> :role_defs, :default => p.role.name))
       end
     end
@@ -167,17 +167,15 @@ class PermissionsController < ApplicationController
 
   private
 
-  def load_users
-    sort_order = params[:sort_by].nil? ? "login" : params[:sort_by]
-    @users = paginate_collection(User.all(:order => sort_order), params[:page])
+  def load_entities
+    sort_order = params[:sort_by].nil? ? "name" : params[:sort_by]
+    @entities = paginate_collection(Entity.all(:order => sort_order), params[:page])
   end
 
   def load_headers
     @header = [
       { :name => '', :sortable => false },
-      { :name => t('users.index.username') },
-      { :name => t('users.index.last_name'), :sortable => false },
-      { :name => t('users.index.first_name'), :sortable => false },
+      { :name => t('permissions.name') },
       { :name => t('role'), :sortable => false }
     ]
   end
diff --git a/src/app/controllers/pool_families_controller.rb b/src/app/controllers/pool_families_controller.rb
index 2d35080..dcbc59f 100644
--- a/src/app/controllers/pool_families_controller.rb
+++ b/src/app/controllers/pool_families_controller.rb
@@ -115,9 +115,10 @@ class PoolFamiliesController < ApplicationController
     end
 
     @provider_accounts = ProviderAccount.
-      list_for_user(current_user, Privilege::USE).
-      where('provider_accounts.id not in (?)', @pool_family.provider_accounts.empty? ?
-                               0 : @pool_family.provider_accounts.map(&:id))
+      list_for_user(current_session, current_user, Privilege::USE).
+      where('provider_accounts.id not in (?)',
+            @pool_family.provider_accounts.empty? ?
+            0 : @pool_family.provider_accounts.map(&:id))
 
     added = []
     not_added = []
@@ -207,7 +208,9 @@ class PoolFamiliesController < ApplicationController
   end
 
   def load_pool_families
-    @pool_families = PoolFamily.list_for_user(current_user, Privilege::VIEW).order(sort_column(PoolFamily) + ' ' + sort_direction)
+    @pool_families = PoolFamily.list_for_user(current_session, current_user,
+                                              Privilege::VIEW).
+      order(sort_column(PoolFamily) + ' ' + sort_direction)
   end
 
   def load_pool_family_tabs
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb
index 5229dfd..20a5572 100644
--- a/src/app/controllers/pools_controller.rb
+++ b/src/app/controllers/pools_controller.rb
@@ -43,31 +43,44 @@ class PoolsController < ApplicationController
     details_tab_name = params[:details_tab].blank? ? 'pools' : params[:details_tab]
     @details_tab = @tabs.find {|t| t[:id] == details_tab_name} || @tabs.first[:name].downcase
 
-    @user_pools = Pool.list_for_user(current_user, Privilege::CREATE, Deployment)
+    @user_pools = Pool.list_for_user(current_session, current_user,
+                                     Privilege::CREATE, Deployment)
 
     if filter_view?
       case @details_tab[:id]
       when 'pools'
-        @pools = paginate_collection(Pool.includes(:deployments, :instances).
-                                     apply_filters(:preset_filter_id => params[:pools_preset_filter], :search_filter => params[:pools_search]).
-                                     list_for_user(current_user, Privilege::VIEW).list(sort_column(Pool), sort_direction),
-                                     params[:page], PER_PAGE)
+        @pools = paginate_collection(
+          Pool.includes(:deployments, :instances).
+            apply_filters(:preset_filter_id => params[:pools_preset_filter],
+                          :search_filter => params[:pools_search]).
+            list_for_user(current_session, current_user, Privilege::VIEW).
+            list(sort_column(Pool), sort_direction),
+          params[:page], PER_PAGE)
       when 'instances'
         params[:instances_preset_filter] = "" unless params[:instances_preset_filter]
-        @instances = paginate_collection(Instance.includes({:provider_account => :provider}).
-                                         apply_filters(:preset_filter_id => params[:instances_preset_filter], :search_filter => params[:instances_search]).
-                                         list_for_user(current_user, Privilege::VIEW).list(sort_column(Instance), sort_direction),
-                                         params[:page], PER_PAGE)
+        @instances = paginate_collection(
+          Instance.includes({:provider_account => :provider}).
+            apply_filters(:preset_filter_id => params[:instances_preset_filter],
+                          :search_filter => params[:instances_search]).
+            list_for_user(current_session, current_user, Privilege::VIEW).
+            list(sort_column(Instance), sort_direction),
+          params[:page], PER_PAGE)
       when 'deployments'
-        @deployments = paginate_collection(Deployment.includes(:pool, :instances).
-                                           apply_filters(:preset_filter_id => params[:deployments_preset_filter], :search_filter => params[:deployments_search]).
-                                           list_for_user(current_user, Privilege::VIEW).list(sort_column(Deployment), sort_direction),
-                                           params[:page], PER_PAGE)
+        @deployments = paginate_collection(
+          Deployment.includes(:pool, :instances).
+            apply_filters(:preset_filter_id =>
+                            params[:deployments_preset_filter],
+                          :search_filter => params[:deployments_search]).
+            list_for_user(current_session, current_user, Privilege::VIEW).
+            list(sort_column(Deployment), sort_direction),
+          params[:page], PER_PAGE)
       end
     else
-      @pools = paginate_collection(Pool.includes(:deployments, :instances, :quota, :catalogs).
-                                   list_for_user(current_user, Privilege::VIEW).list(sort_column(Pool), sort_direction),
-                                   params[:page], PER_PAGE)
+      @pools = paginate_collection(
+        Pool.includes(:deployments, :instances, :quota, :catalogs).
+          list_for_user(current_session, current_user, Privilege::VIEW).
+          list(sort_column(Pool), sort_direction),
+        params[:page], PER_PAGE)
     end
 
     statistics
@@ -104,14 +117,18 @@ class PoolsController < ApplicationController
     @title = t('pools.header_show.pool_name', :name => @pool.name)
     save_breadcrumb(pool_path(@pool, :viewstate => viewstate_id), @pool.name)
     require_privilege(Privilege::VIEW, @pool)
-    @statistics = @pool.statistics(current_user)
+    @statistics = @pool.statistics(current_session, current_user)
 
     if params[:details_tab]
       case params[:details_tab]
         when 'images'
-          #this case covers fetching of unique images and constructing collection for filter table
-          @header = [{:name => "catalog"}, {:name => "deployable"}, {:name => "image"}, {:name => "provider_image"}]
-          @catalog_images = @pool.catalog_images_collection(@pool.catalogs.list_for_user(current_user, Privilege::VIEW))
+          # this case covers fetching of unique images and constructing
+          # collection for filter table
+          @header = [{:name => "catalog"}, {:name => "deployable"},
+                     {:name => "image"}, {:name => "provider_image"}]
+          @catalog_images = @pool.catalog_images_collection(
+            @pool.catalogs.list_for_user(current_session, current_user,
+                                         Privilege::VIEW))
         when 'deployments'
           @view = filter_view? ? 'deployments/list' : 'deployments/pretty_view'
       end      
@@ -129,17 +146,24 @@ class PoolsController < ApplicationController
 
     details_tab_name = params[:details_tab].blank? ? 'deployments' : params[:details_tab]
     @details_tab = @tabs.find {|t| t[:id] == details_tab_name} || @tabs.first[:name].downcase
-    @deployments = paginate_collection(@pool.deployments.includes(:owner, :pool, :instances, :events).
-                                                         apply_filters(:preset_filter_id => params[:deployments_preset_filter], :search_filter => params[:deployments_search]).
-                                                         list_for_user(current_user, Privilege::VIEW),
-                                       params[:page], PER_PAGE) if @details_tab[:id] == 'deployments'
+    if @details_tab[:id] == 'deployments'
+      @deployments = paginate_collection(
+        @pool.deployments.includes(:owner, :pool, :instances, :events).
+          apply_filters(:preset_filter_id => params[:deployments_preset_filter],
+                        :search_filter => params[:deployments_search]).
+          list_for_user(current_session, current_user, Privilege::VIEW),
+        params[:page], PER_PAGE)
+    end
     @view = @details_tab[:view]
     respond_to do |format|
       format.html { render :action => :show}
       format.js { render :partial => @view }
       format.json do
-        deployments = paginate_collection(@pool.deployments.list_for_user(current_user, Privilege::VIEW), params[:page], PER_PAGE).
-                                                            map{ |deployment| view_context.deployment_for_mustache(deployment) }
+        deployments = paginate_collection(
+            @pool.deployments.list_for_user(current_session, current_user,
+                                            Privilege::VIEW),
+            params[:page], PER_PAGE).
+          map{ |deployment| view_context.deployment_for_mustache(deployment) }
         render :json => @pool.as_json.merge({:deployments => deployments})
       end
     end
@@ -151,7 +175,8 @@ class PoolsController < ApplicationController
     @pool.pool_family = PoolFamily.find(params[:pool_family_id]) unless params[:pool_family_id].blank?
     require_privilege(Privilege::CREATE, Pool, @pool.pool_family)
     @quota = Quota.new
-    @pool_families = PoolFamily.list_for_user(current_user, Privilege::CREATE, Pool)
+    @pool_families = PoolFamily.list_for_user(current_session, current_user,
+                                              Privilege::CREATE, Pool)
     respond_to do |format|
       format.html
       format.json { render :json => @pool }
@@ -334,7 +359,9 @@ class PoolsController < ApplicationController
     # (But if it's nil, we want to show all instances)
     params[:state] = 'running' unless params.keys.include?('state')
     conditions = params[:state].present? ? ['state=?', params[:state]] : ''
-    @instances = @pool.instances.list_for_user(current_user, Privilege::VIEW).find(:all, :conditions => conditions)
+    @instances = @pool.instances.list_for_user(current_session, current_user,
+                                               Privilege::VIEW).
+      where(conditions)
   end
 
   def set_quota
diff --git a/src/app/controllers/provider_accounts_controller.rb b/src/app/controllers/provider_accounts_controller.rb
index 7b51356..095b534 100644
--- a/src/app/controllers/provider_accounts_controller.rb
+++ b/src/app/controllers/provider_accounts_controller.rb
@@ -212,6 +212,10 @@ class ProviderAccountsController < ApplicationController
   end
 
   def load_accounts
-    @provider_accounts = ProviderAccount.apply_filters(:preset_filter_id => params[:provider_accounts_preset_filter], :search_filter => params[:provider_accounts_search]).list_for_user(current_user, Privilege::VIEW)
+    @provider_accounts = ProviderAccount.
+      apply_filters(:preset_filter_id =>
+                      params[:provider_accounts_preset_filter],
+                    :search_filter => params[:provider_accounts_search]).
+      list_for_user(current_session, current_user, Privilege::VIEW)
   end
 end
diff --git a/src/app/controllers/providers_controller.rb b/src/app/controllers/providers_controller.rb
index e96ec34..4073dd8 100644
--- a/src/app/controllers/providers_controller.rb
+++ b/src/app/controllers/providers_controller.rb
@@ -178,7 +178,8 @@ class ProvidersController < ApplicationController
   end
 
   def load_providers
-    @providers = Provider.list_for_user(current_user, Privilege::VIEW)
+    @providers = Provider.list_for_user(current_session, current_user,
+                                        Privilege::VIEW)
   end
 
   def disable_provider
@@ -266,7 +267,13 @@ class ProvidersController < ApplicationController
     details_tab_name = params[:details_tab].blank? ? 'connectivity' : params[:details_tab]
     @details_tab = @tabs.find {|t| t[:id] == details_tab_name} || @tabs.first[:name].downcase
 
-    @provider_accounts = @provider.provider_accounts.apply_filters(:preset_filter_id => params[:provider_accounts_preset_filter], :search_filter => params[:provider_accounts_search]).list_for_user(current_user, Privilege::VIEW) if @details_tab[:id] == 'accounts'
+    if @details_tab[:id] == 'accounts'
+      @provider_accounts = @provider.provider_accounts.
+        apply_filters(:preset_filter_id =>
+                        params[:provider_accounts_preset_filter],
+                      :search_filter => params[:provider_accounts_search]).
+        list_for_user(current_session, current_user, Privilege::VIEW)
+    end
     #@permissions = @provider.permissions if @details_tab[:id] == 'roles'
 
     @view = @details_tab[:view]
diff --git a/src/app/controllers/realm_mappings_controller.rb b/src/app/controllers/realm_mappings_controller.rb
index 41d53a1..ca68e0b 100644
--- a/src/app/controllers/realm_mappings_controller.rb
+++ b/src/app/controllers/realm_mappings_controller.rb
@@ -53,11 +53,12 @@ class RealmMappingsController < ApplicationController
 
   def load_backend_targets
     @backend_targets = if @realm_target.realm_or_provider_type == 'Realm'
-      Provider.list_for_user(current_user, Privilege::USE).collect do |provider|
+      Provider.list_for_user(current_session, current_user,
+                             Privilege::USE).collect do |provider|
         provider.realms
       end.flatten
     else
-      Provider.list_for_user(current_user, Privilege::USE)
+      Provider.list_for_user(current_session, current_user, Privilege::USE)
     end
 
   end
diff --git a/src/app/controllers/realms_controller.rb b/src/app/controllers/realms_controller.rb
index 1ee37d8..695f1e2 100644
--- a/src/app/controllers/realms_controller.rb
+++ b/src/app/controllers/realms_controller.rb
@@ -140,11 +140,13 @@ class RealmsController < ApplicationController
 
   def load_backend_realms
     #TODO: list only realms user has permission on
-    @backend_realms = Provider.list_for_user(current_user, Privilege::USE).collect do |provider|
+    @backend_realms = Provider.list_for_user(current_session, current_user,
+                                             Privilege::USE).collect do |provider|
       provider.realms
     end.flatten
 
-    @providers = Provider.list_for_user(current_user, Privilege::USE)
+    @providers = Provider.list_for_user(current_session, current_user,
+                                        Privilege::USE)
   end
 
   def load_realms
diff --git a/src/app/helpers/mustache_helper.rb b/src/app/helpers/mustache_helper.rb
index 78a663e..c4785dd 100644
--- a/src/app/helpers/mustache_helper.rb
+++ b/src/app/helpers/mustache_helper.rb
@@ -20,7 +20,8 @@
 module MustacheHelper
 
   def user_info_for_mustache
-    user_pools = Pool.list_for_user(current_user, Privilege::CREATE, Deployment);
+    user_pools = Pool.list_for_user(current_session, current_user,
+                                    Privilege::CREATE, Deployment);
     user_instances = current_user.owned_instances
     user_available_quota = current_user.quota.maximum_running_instances
     {
@@ -116,8 +117,11 @@ module MustacheHelper
       },
 
       :user_deployments => paginate_collection(pool.deployments.
-                                               list_for_user(current_user, Privilege::VIEW).
-                                               ascending_by_name, params[:page], PER_PAGE)
+                                               list_for_user(current_session,
+                                                             current_user,
+                                                             Privilege::VIEW).
+                                               ascending_by_name, params[:page],
+                                               PER_PAGE)
     }
   end
 
diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb
index 78af946..0cf1137 100644
--- a/src/app/models/deployment.rb
+++ b/src/app/models/deployment.rb
@@ -210,13 +210,13 @@ class Deployment < ActiveRecord::Base
     @launch_parameters = launch_parameters
   end
 
-  def create_and_launch(user)
+  def create_and_launch(session, user)
     begin
       rollback_active_record_state! do
         # deployment's attrs are not reset on rollback,
         # rollback_active_record_state! takes care of this
         transaction do
-          create_instances_with_params!(user)
+          create_instances_with_params!(session, user)
           launch!(user)
         end
       end
@@ -332,11 +332,11 @@ class Deployment < ActiveRecord::Base
 
   # we try to create an instance for each assembly and check
   # if a match is found
-  def check_assemblies_matches(user)
+  def check_assemblies_matches(session, user)
     errs = []
     begin
       deployable_xml.assemblies.each do |assembly|
-        hw_profile = permissioned_frontend_hwprofile(user, assembly.hwp)
+        hw_profile = permissioned_frontend_hwprofile(session, user, assembly.hwp)
         raise I18n.t('deployments.flash.error.no_hwp_permission', :hwp => assembly.hwp) unless hw_profile
         instance = Instance.new(
           :deployment => self,
@@ -503,8 +503,8 @@ class Deployment < ActiveRecord::Base
     end
   end
 
-  def permissioned_frontend_hwprofile(user, hwp_name)
-    HardwareProfile.list_for_user(user, Privilege::VIEW).where('hardware_profiles.name = :name AND provider_id IS NULL', {:name => hwp_name}).first
+  def permissioned_frontend_hwprofile(session, user, hwp_name)
+    HardwareProfile.list_for_user(session, user, Privilege::VIEW).where('hardware_profiles.name = :name AND provider_id IS NULL', {:name => hwp_name}).first
   end
 
   def inject_launch_parameters
@@ -570,10 +570,10 @@ class Deployment < ActiveRecord::Base
     self[:pool_family_id] = pool.pool_family_id
   end
 
-  def create_instances_with_params!(user)
+  def create_instances_with_params!(session, user)
     errors = {}
     deployable_xml.assemblies.each do |assembly|
-      hw_profile = permissioned_frontend_hwprofile(user, assembly.hwp)
+      hw_profile = permissioned_frontend_hwprofile(session, user, assembly.hwp)
       raise I18n.t('deployments.flash.error.no_hwp_permission', :hwp => assembly.hwp) unless hw_profile
       Instance.transaction do
         instance = Instance.create!(
diff --git a/src/app/models/derived_permission.rb b/src/app/models/derived_permission.rb
index 06e7e8e..b7a2530 100644
--- a/src/app/models/derived_permission.rb
+++ b/src/app/models/derived_permission.rb
@@ -47,9 +47,9 @@ class DerivedPermission < ActiveRecord::Base
   belongs_to :role
   validates_presence_of :role_id
 
-  # user is copied from source permission
-  belongs_to :user
-  validates_presence_of :user_id
+  # entity is copied from source permission
+  belongs_to :entity
+  validates_presence_of :entity_id
 
   validates_uniqueness_of :permission_id, :scope => [:permission_object_id,
                                                      :permission_object_type]
diff --git a/src/app/models/entity.rb b/src/app/models/entity.rb
new file mode 100644
index 0000000..bbc56fe
--- /dev/null
+++ b/src/app/models/entity.rb
@@ -0,0 +1,29 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+class Entity < ActiveRecord::Base
+  belongs_to :entity_target, :polymorphic => true
+  validates_presence_of :entity_target_id
+  has_many :session_entities, :dependent => :destroy
+  has_many :permissions, :dependent => :destroy
+  has_many :derived_permissions, :dependent => :destroy
+
+  # type-specific associations
+  belongs_to :user, :class_name => "User", :foreign_key => "entity_target_id"
+  belongs_to :user_group, :class_name => "UserGroup",
+                          :foreign_key => "entity_target_id"
+
+end
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 472b24c..fd14406 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -275,14 +275,14 @@ class Instance < ActiveRecord::Base
     end
   end
 
-  def self.get_user_instances_stats(user)
+  def self.get_user_instances_stats(session, user)
     stats = {
       :running_instances => 0,
       :stopped_instances => 0,
     }
 
     instances = []
-    pools = Pool.list_for_user(user, Privilege::VIEW, Instance)
+    pools = Pool.list_for_user(session, user, Privilege::VIEW, Instance)
     pools.each{|pool| pool.instances.each {|i| instances << i}}
     instances.each do |i|
       if i.state == Instance::STATE_RUNNING
diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb
index 89b2268..048f7a5 100644
--- a/src/app/models/permission.rb
+++ b/src/app/models/permission.rb
@@ -31,14 +31,14 @@
 
 class Permission < ActiveRecord::Base
   belongs_to :role
-  belongs_to :user
+  belongs_to :entity
 
   validates_presence_of :role_id
 
-  validates_presence_of :user_id
-  validates_uniqueness_of :user_id, :scope => [:permission_object_id,
-                                               :permission_object_type,
-                                               :role_id]
+  validates_presence_of :entity_id
+  validates_uniqueness_of :entity_id, :scope => [:permission_object_id,
+                                                 :permission_object_type,
+                                                 :role_id]
 
   belongs_to :permission_object,      :polymorphic => true
   # type-specific associations
@@ -67,6 +67,13 @@ class Permission < ActiveRecord::Base
 
   after_save :update_derived_permissions
 
+  def user
+    entity.user
+  end
+  def user_group
+    entity.user_group
+  end
+
   def update_derived_permissions
     new_derived_permission_objects = permission_object.derived_subtree(role)
     old_derived_permissions = derived_permissions
@@ -74,7 +81,7 @@ class Permission < ActiveRecord::Base
       if new_derived_permission_objects.delete(derived_perm.permission_object)
         # object is in both old and new list -- update as necessary
         derived_perm.role = role
-        derived_perm.user_id = user_id
+        derived_perm.entity_id = entity_id
         derived_perm.save!
       else
         # object is in old but not new list -- remove it
@@ -85,7 +92,7 @@ class Permission < ActiveRecord::Base
       unless DerivedPermission.where(:permission_id => id,
                                      :permission_object_id => perm_obj.id,
                                      :permission_object_type => perm_obj.class.name).any?
-        derived_perm = DerivedPermission.new(:user_id => user_id,
+        derived_perm = DerivedPermission.new(:entity_id => entity_id,
                                              :role_id => role_id,
                                              :permission_object => perm_obj,
                                              :permission => self)
diff --git a/src/app/models/permissioned_object.rb b/src/app/models/permissioned_object.rb
index ecab307..4f881ee 100644
--- a/src/app/models/permissioned_object.rb
+++ b/src/app/models/permissioned_object.rb
@@ -16,24 +16,30 @@
 
 module PermissionedObject
 
-  def has_privilege(user, action, target_type=nil)
-    return false if user.nil? or action.nil?
+  def has_privilege(session, user, action, target_type=nil)
+    return false if session.nil? or user.nil? or action.nil?
     target_type = self.class.default_privilege_target_type if target_type.nil?
-    if derived_permissions.includes(:role => :privileges).where(
-      ["derived_permissions.user_id=:user and
+    if derived_permissions.includes(:role => :privileges,
+                                    :entity => :session_entities).where(
+      ["session_entities.user_id=:user and
+        session_entities.session_id=:session and
         privileges.target_type=:target_type and
         privileges.action=:action",
         { :user => user.id,
+          :session => session.id,
           :target_type => target_type.name,
           :action => action}]).any?
       return true
     else
       BasePermissionObject.general_permission_scope.permissions.
-        includes(:role => :privileges).where(
-      ["permissions.user_id=:user and
+        includes(:role => :privileges,
+                 :entity => :session_entities).where(
+      ["session_entities.user_id=:user and
+        session_entities.session_id=:session and
         privileges.target_type=:target_type and
         privileges.action=:action",
         { :user => user.id,
+          :session => session.id,
           :target_type => target_type.name,
           :action => action}]).any?
     end
@@ -58,7 +64,7 @@ module PermissionedObject
       perm_obj.permissions.each do |permission|
         if permission.role.privilege_target_match(self.class.default_privilege_target_type)
           unless old_derived_permissions.delete(permission.id)
-            derived_permissions.create(:user_id => permission.user_id,
+            derived_permissions.create(:entity_id => permission.entity_id,
                                        :role_id => permission.role_id,
                                        :permission => permission)
           end
@@ -81,7 +87,8 @@ module PermissionedObject
                                             { :assign => true,
                                               :scope => self.class.default_privilege_target_type.name}])
     roles.each do |role|
-      Permission.create!(:role => role, :user => user, :permission_object => self)
+      Permission.create!(:role => role, :entity => user.entity,
+                         :permission_object => self)
     end
     self.reload
   end
@@ -106,16 +113,23 @@ module PermissionedObject
       def self.default_privilege_target_type
         self
       end
-      def self.list_for_user(user, action, target_type=self.default_privilege_target_type)
-        return where("1=0") if user.nil? or action.nil? or target_type.nil?
-        if BasePermissionObject.general_permission_scope.has_privilege(user, action, target_type)
+      def self.list_for_user(session, user, action,
+                             target_type=self.default_privilege_target_type)
+        if session.nil? or user.nil? or action.nil? or target_type.nil?
+          return where("1=0")
+        end
+        if BasePermissionObject.general_permission_scope.
+            has_privilege(session, user, action, target_type)
           scoped
         else
-          includes([:derived_permissions => {:role => :privileges}]).
-            where("derived_permissions.user_id=:user and
+          includes([:derived_permissions => {:role => :privileges,
+                                             :entity => :session_entities}]).
+            where("session_entities.user_id=:user and
+                   session_entities.session_id=:session and
                    privileges.target_type=:target_type and
                    privileges.action=:action",
                   {:user => user.id,
+                   :session => session.id,
                    :target_type => target_type.name,
                    :action => action})
         end
diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb
index 24b4b68..1745325 100644
--- a/src/app/models/pool.rb
+++ b/src/app/models/pool.rb
@@ -98,7 +98,7 @@ class Pool < ActiveRecord::Base
   end
 
   # TODO: Implement Alerts and Updates
-  def statistics(user = nil)
+  def statistics(session=nil, user = nil)
     # TODO - Need to set up cache invalidation before this is safe
     #Rails.cache.fetch("pool-#{id}-statistics") do
     max = quota.maximum_running_instances
@@ -106,7 +106,7 @@ class Pool < ActiveRecord::Base
     avail = max - total unless max.nil?
     all_failed = instances.failed
     failed = (user.nil? || all_failed.empty? ? all_failed :
-              all_failed.list_for_user(user, Privilege::VIEW))
+              all_failed.list_for_user(session, user, Privilege::VIEW))
     pool_family_quota_percent = pool_family.quota.percentage_used quota.running_instances
     statistics = {
       :cloud_providers => instances.includes(:provider_account).collect{|i| i.provider_account}.uniq.count,
diff --git a/src/app/models/session_entity.rb b/src/app/models/session_entity.rb
new file mode 100644
index 0000000..e7bf869
--- /dev/null
+++ b/src/app/models/session_entity.rb
@@ -0,0 +1,47 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+class SessionEntity < ActiveRecord::Base
+  belongs_to :user
+  belongs_to :session, :class_name => "ActiveRecord::SessionStore::Session"
+  belongs_to :entity
+
+  validates_presence_of :user_id
+  validates_presence_of :session_id
+  validates_presence_of :entity_id
+  validates_uniqueness_of :entity_id, :scope => [:user_id, :session_id]
+
+  def self.update_session(session, user)
+    self.transaction do
+      # skips callbacks, which should be fine here
+      self.delete_all(:session_id => session.id)
+      self.add_to_session(session, user)
+    end
+  end
+
+  def self.add_to_session(session, user)
+    return unless user
+    # create mapping for user-level permissions
+    SessionEntity.create!(:session => session, :user => user,
+                          :entity => user.entity)
+    # create mappings for local groups
+    user.user_groups.each do |ug|
+      SessionEntity.create!(:session => session, :user => user,
+                            :entity => ug.entity)
+    end
+    # TODO: add entities for ldap groups
+  end
+end
diff --git a/src/app/models/user.rb b/src/app/models/user.rb
index 66565a7..6c1cfb7 100644
--- a/src/app/models/user.rb
+++ b/src/app/models/user.rb
@@ -58,16 +58,21 @@ class User < ActiveRecord::Base
   # for them
   attr_accessor :ignore_password
 
-  has_many :permissions, :dependent => :destroy
-  has_many :derived_permissions, :dependent => :destroy
+  has_many :permissions, :through => :entity
+  has_many :derived_permissions, :through => :entities
   has_many :owned_instances, :class_name => "Instance", :foreign_key => "owner_id"
   has_many :deployments, :foreign_key => "owner_id"
   has_many :view_states
+  has_and_belongs_to_many :user_groups, :join_table => "members_user_groups",
+                                        :foreign_key => "member_id"
+  has_one :entity, :as => :entity_target, :dependent => :destroy
+  has_many :session_entities, :dependent => :destroy
 
   belongs_to :quota, :autosave => true, :dependent => :destroy
   accepts_nested_attributes_for :quota
 
   before_validation :strip_whitespace
+  after_save :update_entity
 
   validates_presence_of :quota
   validates_length_of :first_name, :maximum => 255, :allow_blank => true
@@ -161,4 +166,10 @@ class User < ActiveRecord::Base
   def strip_whitespace
     self.login = self.login.strip unless self.login.nil?
   end
+
+  def update_entity
+    self.entity = Entity.new(:entity_target => self) unless self.entity
+    self.entity.name = "#{self.first_name} #{self.last_name} (#{self.login})"
+    self.entity.save!
+  end
 end
diff --git a/src/app/models/user_group.rb b/src/app/models/user_group.rb
new file mode 100644
index 0000000..293d0db
--- /dev/null
+++ b/src/app/models/user_group.rb
@@ -0,0 +1,45 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+class UserGroup < ActiveRecord::Base
+  # name will correspond to the group name if we're using LDAP, otherwise it's
+  # entered by the admin creating the group
+
+  # members association is only maintained for local groups
+  has_and_belongs_to_many :members, :join_table => "members_user_groups",
+                                    :class_name => "User",
+                                    :association_foreign_key => "member_id"
+  has_one :entity, :as => :entity_target, :dependent => :destroy
+
+  MEMBERSHIP_SOURCE_LDAP = "LDAP"
+  MEMBERSHIP_SOURCE_LOCAL = "local"
+  MEMBERSHIP_SOURCES = [MEMBERSHIP_SOURCE_LOCAL, MEMBERSHIP_SOURCE_LDAP]
+
+  validates_presence_of :name
+  # scope name by membership_source to prevent errors if users are later added
+  # to external ldap groups that have the same name as local groups
+  validates_uniqueness_of :name, :scope => :membership_source
+
+  validates_presence_of :membership_source
+  validates_inclusion_of :membership_source, :in => MEMBERSHIP_SOURCES
+  after_save :update_entity
+
+  def update_entity
+    self.entity = Entity.new(:entity_target => self) unless self.entity
+    self.entity.name = "#{self.name} (#{self.membership_source})"
+    self.entity.save!
+  end
+end
diff --git a/src/app/services/application_service.rb b/src/app/services/application_service.rb
index 94c8011..e8490b5 100644
--- a/src/app/services/application_service.rb
+++ b/src/app/services/application_service.rb
@@ -45,7 +45,7 @@ module ApplicationService
     end
     perm_obj=@perm_obj if perm_obj.nil?
     perm_obj=BasePermissionObject.general_permission_scope if perm_obj.nil?
-    perm_obj.has_privilege(current_user, action, target_type)
+    perm_obj.has_privilege(current_session, current_user, action, target_type)
   end
 
   # Require a given privilege level to view this page
diff --git a/src/app/services/registration_service.rb b/src/app/services/registration_service.rb
index d67ab0d..a4753f9 100644
--- a/src/app/services/registration_service.rb
+++ b/src/app/services/registration_service.rb
@@ -39,7 +39,7 @@ class RegistrationService
             obj_key, role_key = x.split(/, ?/)
             default_obj = MetadataObject.lookup(obj_key)
             default_role = MetadataObject.lookup(role_key)
-            Permission.create!(:user => @user, :role => default_role, :permission_object => default_obj)
+            Permission.create!(:entity => @user.entity, :role => default_role, :permission_object => default_obj)
           end
         return true
       rescue ActiveRecord::RecordInvalid => e
diff --git a/src/app/views/permissions/_form.html.haml b/src/app/views/permissions/_form.html.haml
index 6027f39..95aa05d 100644
--- a/src/app/views/permissions/_form.html.haml
+++ b/src/app/views/permissions/_form.html.haml
@@ -5,12 +5,10 @@
   = hidden_field_tag :use_tabs, @use_tabs
   = link_to t('cancel'), @return_path, :class => 'button danger'
   = restful_submit_tag t('permissions.form.grant_access'), "create", permissions_path, 'POST', :id => 'save_button', :class => 'button'
-= filter_table(@header, @users) do |user|
+= filter_table(@header, @entities) do |entity|
   %tr{:class => cycle('nostripe','stripe')}
     %td
       -# - selected = params[:select] == 'all'
-      -#  = check_box_tag "user_selected[]", user.id, selected, :id => "user_checkbox_#{user.id}"
-    %td= link_to user.login, user_path(user)
-    %td= user.last_name
-    %td= user.first_name
-    %td= select_tag "user_role_selected[]", options_for_select([['', "#{user.id},"]] + @roles.map {|r| [t(r.name, :scope=> :role_defs, :default => r.name), "#{user.id},#{r.id}" ] }, :disabled => @permission_object.permissions.where(:user_id=>user.id).collect {|p| "#{user.id},#{p.role.id}"}), :id => "user_role_selected_#{user.id}"
+      -#  = check_box_tag "entity_selected[]", entity.id, selected, :id => "entity_checkbox_#{entity.id}"
+    %td= link_to entity.name, (entity.user ? user_path(entity.user) : user_group_path(entity.user_group))
+    %td= select_tag "entity_role_selected[]", options_for_select([['', "#{entity.id},"]] + @roles.map {|r| [t(r.name, :scope=> :role_defs, :default => r.name), "#{entity.id},#{r.id}" ] }, :disabled => @permission_object.permissions.where(:entity_id=>entity.id).collect {|p| "#{entity.id},#{p.role.id}"}), :id => "entity_role_selected_#{entity.id}"
diff --git a/src/app/views/permissions/_permissions.html.haml b/src/app/views/permissions/_permissions.html.haml
index 1ace6c8..b1e18f7 100644
--- a/src/app/views/permissions/_permissions.html.haml
+++ b/src/app/views/permissions/_permissions.html.haml
@@ -34,11 +34,9 @@
         - if check_privilege(Privilege::PERM_SET)
           - selected = params[:select] == 'all'
           = check_box_tag "permission_selected[]", permission.id, selected, :id => "permission_checkbox_#{permission.id}"
-    %td= link_to permission.user.login, user_path(permission.user)
-    %td= permission.user.last_name
-    %td= permission.user.first_name
+    %td= link_to permission.entity.name, (permission.entity.user ? user_path(permission.entity.user) : user_group_path(permission.entity.user_group))
     - if not(@show_inherited or @show_global) && check_privilege(Privilege::PERM_SET)
-      %td= select_tag "permission_role_selected[]", options_for_select(@roles.map {|r| [ t(r.name, :scope=> :role_defs, :default => r.name), "#{permission.id},#{r.id}" ] }, :selected => "#{permission.id},#{permission.role.id}", :disabled => @permission_object.permissions.where(["user_id = ? and role_id != ?", permission.user_id, permission.role_id]).collect {|p| "#{permission.id},#{p.role.id}"}), :id => "permission_role_selected_#{permission.id}"
+      %td= select_tag "permission_role_selected[]", options_for_select(@roles.map {|r| [ t(r.name, :scope=> :role_defs, :default => r.name), "#{permission.id},#{r.id}" ] }, :selected => "#{permission.id},#{permission.role.id}", :disabled => @permission_object.permissions.where(["entity_id = ? and role_id != ?", permission.entity_id, permission.role_id]).collect {|p| "#{permission.id},#{p.role.id}"}), :id => "permission_role_selected_#{permission.id}"
       :javascript
         $("#permission_role_selected_#{permission.id}").change(function () { $("#perm_edit_button").click(); } );
 
diff --git a/src/app/views/pools/_pretty_list.html.haml b/src/app/views/pools/_pretty_list.html.haml
index 7061af6..4e16b69 100644
--- a/src/app/views/pools/_pretty_list.html.haml
+++ b/src/app/views/pools/_pretty_list.html.haml
@@ -7,7 +7,7 @@
       %header{:class => "pool-header-#{pool.id}"}
         = render :partial => 'pretty_list_header', :mustache => pool_for_mustache(pool)
       %div.content
-        - deployments = paginate_collection(pool.deployments.includes(:owner, :pool, :instances, :events).list_for_user(current_user, Privilege::VIEW).ascending_by_name, params[:page], PER_PAGE)
+        - deployments = paginate_collection(pool.deployments.includes(:owner, :pool, :instances, :events).list_for_user(current_session, current_user, Privilege::VIEW).ascending_by_name, params[:page], PER_PAGE)
         = render :partial => 'deployments', :locals => {:pool => pool, :deployments => deployments}
       %ul.content.actions
         %li
diff --git a/src/config/initializers/session.rb b/src/config/initializers/session.rb
new file mode 100644
index 0000000..6d82968
--- /dev/null
+++ b/src/config/initializers/session.rb
@@ -0,0 +1,23 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+module ActiveRecord
+  class SessionStore
+    class Session
+      has_many :session_entities, :dependent => :destroy
+    end
+  end
+end
diff --git a/src/config/initializers/warden.rb b/src/config/initializers/warden.rb
index 37ff2ad..80751ad 100644
--- a/src/config/initializers/warden.rb
+++ b/src/config/initializers/warden.rb
@@ -29,7 +29,7 @@ Rails.configuration.middleware.use RailsWarden::Manager do |config|
   config.scope_defaults(
     :api,
     :strategies   => [SETTINGS_CONFIG[:auth][:strategy].to_sym],
-    :store        => false,
+    :store        => true,
     :action       => 'unauthenticated'
   )
 end
diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
index b198935..dda1b0f 100644
--- a/src/config/locales/en.yml
+++ b/src/config/locales/en.yml
@@ -1247,6 +1247,7 @@ en:
     inherited_access: "Inherited Access"
     inherited_from: "Inherited From"
     revoke_access: "Revoke Access"
+    name: Name
     form:
       grant_access: Grant Access
     new:
diff --git a/src/db/migrate/20110207101100_deployment_roles.rb b/src/db/migrate/20110207101100_deployment_roles.rb
deleted file mode 100644
index 8c1f18f..0000000
--- a/src/db/migrate/20110207101100_deployment_roles.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-#
-#   Copyright 2011 Red Hat, Inc.
-#
-#   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.
-#
-
-class DeploymentRoles < ActiveRecord::Migration
-  VIEW = "view"
-  USE  = "use"
-  MOD  = "modify"
-  CRE  = "create"
-  VPRM = "view_perms"
-  GPRM = "set_perms"
-  NEW_ROLES = {
-    Deployment =>
-     {"Deployment Controller"  => [false, {Deployment => [VIEW,USE],
-                                           Instance   => [VIEW]}],
-      "Deployment Owner"       => [true,  {Deployment => [VIEW,USE,MOD,    VPRM,GPRM],
-                                           Instance   => [VIEW,USE,MOD]}]},
-    Pool =>
-     {"Pool User"              => [false, {Pool         => [VIEW],
-                                           Instance     => [             CRE],
-                                           Deployment   => [             CRE],
-                                           Quota        => [VIEW]}],
-      "Pool Owner"             => [true,  {Pool         => [VIEW,    MOD,    VPRM,GPRM],
-                                           Instance     => [VIEW,USE,MOD,CRE],
-                                           Deployment   => [VIEW,USE,MOD,CRE],
-                                           Quota        => [VIEW]}]},
-   BasePermissionObject =>
-    {"Pool Administrator"     => [false, {Pool         => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           Instance     => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Deployment   => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Quota        => [VIEW,    MOD],
-                                           PoolFamily   => [VIEW,    MOD,CRE,VPRM,GPRM]}],
-      "Administrator"          => [false, {Provider     => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           ProviderAccount => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           HardwareProfile => [      MOD,CRE,VPRM,GPRM],
-                                           Realm        => [     USE,MOD,CRE,VPRM,GPRM],
-                                           User         => [VIEW,    MOD,CRE],
-                                           Pool         => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           Instance     => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Deployment   => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Quota        => [VIEW,    MOD],
-                                           PoolFamily   => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           BasePermissionObject => [ MOD,    VPRM,GPRM]}]}}
-  def self.up
-    unless Role.all.size == 0
-      Role.transaction do
-        NEW_ROLES.each do |role_scope, scoped_hash|
-          scoped_hash.each do |role_name, role_def|
-            role = Role.find_or_initialize_by_name(role_name)
-            role.update_attributes({:name => role_name, :scope => role_scope.name,
-                                     :assign_to_owner => role_def[0]})
-            role.privileges = {}
-            role.save!
-            role_def[1].each do |priv_type, priv_actions|
-              priv_actions.each do |action|
-                Privilege.create!(:role => role, :target_type => priv_type.name,
-                                  :action => action)
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-
-  def self.down
-  end
-end
diff --git a/src/db/migrate/20111122203000_add_deployable_roles.rb b/src/db/migrate/20111122203000_add_deployable_roles.rb
deleted file mode 100644
index 80911e9..0000000
--- a/src/db/migrate/20111122203000_add_deployable_roles.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-#
-#   Copyright 2011 Red Hat, Inc.
-#
-#   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.
-#
-
-class AddDeployableRoles < ActiveRecord::Migration
-  VIEW = "view"
-  USE  = "use"
-  MOD  = "modify"
-  CRE  = "create"
-  VPRM = "view_perms"
-  GPRM = "set_perms"
-  NEW_ROLES = {
-   Deployable =>
-     {"Deployable User"          => [false, {Deployable     => [VIEW,USE]},
-                                     "CatalogEntry User"],
-      "Deployable Owner"         => [true,  {Deployable     => [VIEW,USE,MOD,VPRM,GPRM]},
-                                    "CatalogEntry Owner"]},
-   BasePermissionObject =>
-     {"Deployable Administrator" => [false, {Deployable => [VIEW,USE,MOD,CRE,VPRM,GPRM]},
-                                     "CatalogEntry Administrator"],
-      "Deployable Global User"   => [false, {Deployable=> [VIEW,USE]},
-                                     "CatalogEntry Global User"],
-      "Administrator"          => [false, {Provider     => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           ProviderAccount => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           HardwareProfile => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           Realm        => [     USE,MOD,CRE,VPRM,GPRM],
-                                           User         => [VIEW,    MOD,CRE],
-                                           Pool         => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           Instance     => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Deployment   => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Quota        => [VIEW,    MOD],
-                                           PoolFamily   => [VIEW,    MOD,CRE,VPRM,GPRM],
-                                           Catalog      => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           Deployable => [VIEW,USE,MOD,CRE,VPRM,GPRM],
-                                           BasePermissionObject => [ MOD,    VPRM,GPRM]}]}}
-  def self.up
-    unless Role.all.size == 0
-      Role.transaction do
-        NEW_ROLES.each do |role_scope, scoped_hash|
-          scoped_hash.each do |role_name, role_def|
-            role = Role.find_or_initialize_by_name(role_def[2] ? role_def[2] : role_name)
-            role.update_attributes({:name => role_name, :scope => role_scope.name,
-                                     :assign_to_owner => role_def[0]})
-            role.privileges = {}
-            role.save!
-            role_def[1].each do |priv_type, priv_actions|
-              priv_actions.each do |action|
-                Privilege.create!(:role => role, :target_type => priv_type.name,
-                                  :action => action)
-              end
-            end
-          end
-        end
-
-        MetadataObject.remove("self_service_default_catalog_entry_obj")
-        MetadataObject.remove("self_service_default_catalog_entry_role")
-        MetadataObject.set("self_service_default_deployable_obj",
-                           BasePermissionObject.general_permission_scope)
-        MetadataObject.set("self_service_default_deployable_role",
-                           Role.find_by_name("Deployable Global User"))
-        MetadataObject.set("self_service_perms_list",
-                           "[self_service_default_pool,self_service_default_role], [self_service_default_deployable_obj,self_service_default_deployable_role], [self_service_default_pool_global_user_obj,self_service_default_pool_global_user_role], [self_service_default_catalog_global_user_obj,self_service_default_catalog_global_user_role],[self_service_default_hwp_global_user_obj,self_service_default_hwp_global_user_role] ")
-
-      end
-    end
-  end
-
-  def self.down
-  end
-end
diff --git a/src/db/migrate/20120514121500_create_user_groups.rb b/src/db/migrate/20120514121500_create_user_groups.rb
new file mode 100644
index 0000000..abd32c4
--- /dev/null
+++ b/src/db/migrate/20120514121500_create_user_groups.rb
@@ -0,0 +1,37 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+class CreateUserGroups < ActiveRecord::Migration
+  def self.up
+    create_table :user_groups do |t|
+      t.string :name, :null => false
+      t.string :description
+      # membership_source will be 'ldap' or 'local'
+      t.string :membership_source, :null => false
+      t.integer :lock_version, :default => 0
+
+      t.timestamps
+    end
+    create_table :members_user_groups, :id => false do |t|
+      t.integer :user_group_id, :null => false
+      t.integer :member_id, :null => false
+    end
+  end
+
+  def self.down
+    drop_table :members_user_groups
+    drop_table :user_groups
+  end
+end
diff --git a/src/db/migrate/20120514131500_create_entities.rb b/src/db/migrate/20120514131500_create_entities.rb
new file mode 100644
index 0000000..1270ffe
--- /dev/null
+++ b/src/db/migrate/20120514131500_create_entities.rb
@@ -0,0 +1,38 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+class CreateEntities < ActiveRecord::Migration
+  def self.up
+    create_table :entities do |t|
+      t.string :name
+      t.references :entity_target, :polymorphic => true, :null => false
+
+      t.integer :lock_version, :default => 0
+
+      t.timestamps
+    end
+
+    User.all.each do |u|
+      u.save!
+    end
+    UserGroup.all.each do |ug|
+      ug.save!
+    end
+  end
+
+  def self.down
+    drop_table :entities
+  end
+end
diff --git a/src/db/migrate/20120517131500_create_session_entities.rb b/src/db/migrate/20120517131500_create_session_entities.rb
new file mode 100644
index 0000000..0180018
--- /dev/null
+++ b/src/db/migrate/20120517131500_create_session_entities.rb
@@ -0,0 +1,32 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+class CreateSessionEntities < ActiveRecord::Migration
+  def self.up
+    create_table :session_entities do |t|
+      t.references :user, :null => false
+      t.references :session, :null => false
+      t.references :entity, :null => false
+
+      t.integer :lock_version, :default => 0
+
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :session_entities
+  end
+end
diff --git a/src/db/migrate/20120520151500_change_permission_user.rb b/src/db/migrate/20120520151500_change_permission_user.rb
new file mode 100644
index 0000000..d6af52b
--- /dev/null
+++ b/src/db/migrate/20120520151500_change_permission_user.rb
@@ -0,0 +1,79 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+class ChangePermissionUser < ActiveRecord::Migration
+  def self.up
+    add_column :permissions, :entity_id, :integer
+    add_column :derived_permissions, :entity_id, :integer
+
+    Permission.reset_column_information
+    DerivedPermission.reset_column_information
+
+    Permission.skip_callback(:save, :after, :update_derived_permissions)
+    counter = 0
+    total_perms = Permission.count
+    Permission.all.each do |p|
+      puts "updating permission #{counter +=1} of #{total_perms}"
+      p.entity_id = User.find(p.user_id).entity.id
+      p.save!
+    end
+    Permission.set_callback(:save, :after, :update_derived_permissions)
+    counter = 0
+    total_perms = DerivedPermission.count
+    DerivedPermission.all.each do |p|
+      puts "updating derived permission #{counter +=1} of #{total_perms}"
+      p.entity_id = User.find(p.user_id).entity.id
+      p.save!
+    end
+
+    change_column :permissions, :entity_id, :integer, :null => false
+    change_column :derived_permissions, :entity_id, :integer, :null => false
+
+    remove_column :permissions, :user_id
+    remove_column :derived_permissions, :user_id
+  end
+
+  def self.down
+    add_column :permissions, :user_id, :integer
+    add_column :derived_permissions, :user_id, :integer
+
+    Permission.reset_column_information
+    DerivedPermission.reset_column_information
+
+    Permission.skip_callback(:save, :after, :update_derived_permissions)
+    Permission.all.each do |p|
+      entity = Entity.find(p.entity_id)
+      if entity.entity_target.class == User
+        p.user_id = entity.entity_target.id
+        p.save!
+      end
+    end
+    Permission.set_callback(:save, :after, :update_derived_permissions)
+    DerivedPermission.all.each do |p|
+      entity = Entity.find(p.entity_id)
+      if entity.entity_target.class == User
+        p.user_id = entity.entity_target.id
+        p.save!
+      end
+    end
+
+    change_column :permissions, :user_id, :integer, :null => false
+    change_column :derived_permissions, :user_id, :integer, :null => false
+
+    remove_column :permissions, :entity_id
+    remove_column :derived_permissions, :entity_id
+  end
+end
diff --git a/src/features/step_definitions/authentication.rb b/src/features/step_definitions/authentication.rb
index 533966a..1556400 100644
--- a/src/features/step_definitions/authentication.rb
+++ b/src/features/step_definitions/authentication.rb
@@ -45,8 +45,9 @@ Given /^I am a registered user$/ do
 end
 
 Given /^I am an authorised user$/ do
-  @admin_permission = FactoryGirl.create :admin_permission
-  @user = @admin_permission.user
+  @admin_user = FactoryGirl.create :admin_user
+  @user = @admin_user
+  @admin_permission = FactoryGirl.create :admin_permission, :entity => @user.entity
 end
 
 
@@ -55,8 +56,7 @@ When /^I login$/ do
 end
 
 When /^I login as authorised user$/ do
-  admin_user = @admin_permission.user
-  login(admin_user.login, admin_user.password)
+  login(@admin_user.login, @admin_user.password)
   page.should have_content('Login successful!')
 end
 
@@ -67,6 +67,7 @@ end
 Given /^I am logged in$/ do
   # Warden test helper method
   login_as user
+  visit path_to("the homepage")
 end
 
 Given /^I have successfully logged in$/ do
diff --git a/src/features/step_definitions/permission_steps.rb b/src/features/step_definitions/permission_steps.rb
index 43d3ac1..8620156 100644
--- a/src/features/step_definitions/permission_steps.rb
+++ b/src/features/step_definitions/permission_steps.rb
@@ -18,7 +18,7 @@ Given /^a user "([^\"]*)" exists$/ do |login|
 end
 
 Given /^there is not a permission for the user "([^\"]*)"$/ do |login|
-  Permission.first(:include => 'user', :conditions => ['users.login = ?', login]).should be_nil
+  Permission.first(:include => ['entity' => ['session_entities' => 'user']], :conditions => ['users.login = ?', login]).should be_nil
 end
 
 Given /^there is a permission for the user "([^\"]*)"$/ do |login|
@@ -26,12 +26,12 @@ Given /^there is a permission for the user "([^\"]*)"$/ do |login|
 end
 
 Given /^there is a permission for the user "([^\"]*)" on the pool "([^\"]*)"$/ do |login, pool_name|
-  @pool_user_permission = FactoryGirl.create(:pool_user_permission, :user_id => @user.id,
+  @pool_user_permission = FactoryGirl.create(:pool_user_permission, :entity_id => @user.entity.id,
                                          :permission_object => Pool.find_by_name(pool_name))
 end
 
 Given /^there is a permission for the user "([^\"]*)" on the pool family "([^\"]*)"$/ do |login, pool_family_name|
-  @pool_family_admin_permission = FactoryGirl.create(:pool_family_admin_permission, :user_id => @user.id,
+  @pool_family_admin_permission = FactoryGirl.create(:pool_family_admin_permission, :entity_id => @user.entity.id,
                                          :permission_object => PoolFamily.find_by_name(pool_family_name))
 end
 
@@ -42,5 +42,5 @@ end
 
 When /^(?:|I )select "([^"]*)" role for the user "([^"]*)"$/ do |role_name, user_name|
   user = User.find_by_login(user_name)
-  select(role_name, :from => "user_role_selected_#{user.id}")
+  select(role_name, :from => "entity_role_selected_#{user.entity.id}")
 end
diff --git a/src/features/step_definitions/pool_family_steps.rb b/src/features/step_definitions/pool_family_steps.rb
index dc316ab..dcbb869 100644
--- a/src/features/step_definitions/pool_family_steps.rb
+++ b/src/features/step_definitions/pool_family_steps.rb
@@ -74,5 +74,5 @@ end
 
 Given /^I can view pool family "([^"]*)"$/ do |arg1|
   pool_family = PoolFamily.find_by_name(arg1)  || FactoryGirl.create(:pool_family, :name => arg1)
-  perm = FactoryGirl.create(:pool_family_user_permission, :permission_object => pool_family, :user => @user)
+  perm = FactoryGirl.create(:pool_family_user_permission, :permission_object => pool_family, :entity => @user.entity)
 end
diff --git a/src/features/step_definitions/pool_steps.rb b/src/features/step_definitions/pool_steps.rb
index 8e73121..f575dc2 100644
--- a/src/features/step_definitions/pool_steps.rb
+++ b/src/features/step_definitions/pool_steps.rb
@@ -15,7 +15,7 @@
 #
 Given /^I have Pool Creator permissions on a pool named "([^\"]*)"$/ do |name|
   @pool = FactoryGirl.create(:pool, :name => name)
-  FactoryGirl.create(:pool_creator_permission, :user => @user, :permission_object => @pool)
+  FactoryGirl.create(:pool_creator_permission, :entity => @user.entity, :permission_object => @pool)
 end
 
 Then /^there should be (\d+) pools$/ do |number|
diff --git a/src/lib/tasks/dc_tasks.rake b/src/lib/tasks/dc_tasks.rake
index 083e3e8..b3581c0 100644
--- a/src/lib/tasks/dc_tasks.rake
+++ b/src/lib/tasks/dc_tasks.rake
@@ -95,7 +95,7 @@ namespace :dc do
     end
     permission = Permission.new(:role => Role.find_by_name('base.admin'),
                                 :permission_object => BasePermissionObject.general_permission_scope,
-                                :user => user)
+                                :entity => user.entity)
     if permission.save
       puts "Granting administrator privileges for #{args.login}..."
     else
diff --git a/src/spec/controllers/config_servers_controller_spec.rb b/src/spec/controllers/config_servers_controller_spec.rb
index 53b89df..65d5de0 100644
--- a/src/spec/controllers/config_servers_controller_spec.rb
+++ b/src/spec/controllers/config_servers_controller_spec.rb
@@ -28,7 +28,7 @@ describe ConfigServersController do
       @provider_account = @config_server.provider_account
       @admin_permission = Permission.create :role => Role.find(:first, :conditions => ['name = ?', 'base.provider.admin']),
                                             :permission_object => @provider_account.provider,
-                                            :user => FactoryGirl.create(:provider_admin_user)
+                                            :entity => FactoryGirl.create(:provider_admin_user).entity
       @admin = @admin_permission.user
     end
 
@@ -51,7 +51,7 @@ describe ConfigServersController do
       @provider_account = Factory :mock_provider_account
       @admin_permission = Permission.create :role => Role.find(:first, :conditions => ['name = ?', 'base.provider.admin']),
                                             :permission_object => @provider_account.provider,
-                                            :user => FactoryGirl.create(:provider_admin_user)
+                                            :entity => FactoryGirl.create(:provider_admin_user).entity
       @admin = @admin_permission.user
     end
 
diff --git a/src/spec/controllers/permissions_controller_spec.rb b/src/spec/controllers/permissions_controller_spec.rb
index 050fdf8..95dad2c 100644
--- a/src/spec/controllers/permissions_controller_spec.rb
+++ b/src/spec/controllers/permissions_controller_spec.rb
@@ -31,7 +31,7 @@ describe PermissionsController do
 
     @old_role = FactoryGirl.create(:role)
     @new_role = FactoryGirl.create(:role)
-    @permission = FactoryGirl.create(:permission, :user => @admin, :role => @old_role, :permission_object => @deployable)
+    @permission = FactoryGirl.create(:permission, :entity => @admin.entity, :role => @old_role, :permission_object => @deployable)
 
     post :multi_update, :permission_object_id => @deployable.id, :permission_object_type => @deployable.class.to_s,
         :permission_role_selected => ["#{@permission.id},#{@new_role.id}"], :polymorphic_path_extras => { 'catalog_id' => @catalog.id}
diff --git a/src/spec/controllers/provider_accounts_controller_spec.rb b/src/spec/controllers/provider_accounts_controller_spec.rb
index a875938..fe0ad13 100644
--- a/src/spec/controllers/provider_accounts_controller_spec.rb
+++ b/src/spec/controllers/provider_accounts_controller_spec.rb
@@ -26,7 +26,7 @@ describe ProviderAccountsController do
 
     @admin_permission = Permission.create :role => Role.find(:first, :conditions => ['name = ?', 'base.provider.admin']),
                                           :permission_object => @provider,
-                                          :user => FactoryGirl.create(:provider_admin_user)
+                                          :entity => FactoryGirl.create(:provider_admin_user).entity
     @admin = @admin_permission.user
   end
 
diff --git a/src/spec/factories/permission.rb b/src/spec/factories/permission.rb
index ef2005e..e401fe8 100644
--- a/src/spec/factories/permission.rb
+++ b/src/spec/factories/permission.rb
@@ -17,49 +17,49 @@
 FactoryGirl.define do
 
   factory :permission do
-    after_build { |p| p.user.permissions << p }
+    after_build { |p| p.entity.permissions << p }
   end
 
   factory :admin_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'base.admin']) || FactoryGirl.create(:role, :name => 'base.admin') }
     permission_object { |r| BasePermissionObject.general_permission_scope }
-    user { |r| r.association(:admin_user) }
+    entity { |r| FactoryGirl.create(:admin_user).entity }
   end
 
   factory :provider_admin_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'base.provider.admin']) || FactoryGirl.create(:role, :name => 'base.provider.admin') }
     permission_object { |r| r.association(:mock_provider) }
-    user { |r| r.association(:provider_admin_user) }
+    entity { |r| FactoryGirl.create(:provider_admin_user).entity }
   end
 
   factory :pool_creator_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'base.pool.creator']) || FactoryGirl.create(:role, :name => 'base.pool.creator') }
     permission_object { |r| BasePermissionObject.general_permission_scope }
-    user { |r| r.association(:pool_creator_user) }
+    entity { |r| FactoryGirl.create(:pool_creator_user).entity }
   end
 
   factory :pool_user_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'pool.user']) || FactoryGirl.create(:role, :name => 'pool.user') }
     permission_object { |r| r.association(:pool) }
-    user { |r| r.association(:pool_user) }
+    entity { |r| FactoryGirl.create(:pool_user).entity }
   end
 
   factory :pool_user2_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'pool.user']) || FactoryGirl.create(:role, :name => 'pool.user') }
     permission_object { |r| r.association(:pool) }
-    user { |r| r.association(:pool_user2) }
+    entity { |r| FactoryGirl.create(:pool_user2).entity }
   end
 
   factory :pool_family_user_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'pool_family.user']) || FactoryGirl.create(:role, :name => 'pool_family.user') }
     permission_object { |r| r.association(:pool_family) }
-    user { |r| r.association(:pool_family_user) }
+    entity { |r| FactoryGirl.create(:pool_family_user).entity }
   end
 
   factory :pool_family_admin_permission, :parent => :permission do
     role { |r| Role.first(:conditions => ['name = ?', 'pool_family.admin']) || FactoryGirl.create(:role, :name => 'pool_family.admin') }
     permission_object { |r| r.association(:pool_family) }
-    user { |r| r.association(:pool_family_user) }
+    entity { |r| FactoryGirl.create(:pool_family_user).entity }
   end
 
 end
diff --git a/src/spec/factories/session.rb b/src/spec/factories/session.rb
new file mode 100644
index 0000000..78ff011
--- /dev/null
+++ b/src/spec/factories/session.rb
@@ -0,0 +1,24 @@
+#
+#   Copyright 2012 Red Hat, Inc.
+#
+#   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.
+#
+
+FactoryGirl.define do
+
+  factory :session, :class => ActiveRecord::SessionStore::Session  do
+    session_id 'ee73441902cb9445483e498cb05dc398'
+    data 'BAh7CSIZd2FyZGVuLnVzZXIudXNlci5rZXlpFSIXamF2YXNjcmlwdF9lbmFi\nbGVkVCIQX2NzcmZfdG9rZW4iMVJWYkl2bjBoUEhZdi83aUpmU2FybFdQVWx0\nT0pvNHZOQXFkaXFaNURKRXc9IhBicmVhZGNydW1ic1sGewk6CmNsYXNzIg1j\nYXRhbG9nczoOdmlld3N0YXRlMDoJbmFtZSINQ2F0YWxvZ3M6CXBhdGgiDi9j\nYXRhbG9ncw==\n'
+  end
+
+end
diff --git a/src/spec/models/deployable_spec.rb b/src/spec/models/deployable_spec.rb
index a98eed7..6bc8ffd 100644
--- a/src/spec/models/deployable_spec.rb
+++ b/src/spec/models/deployable_spec.rb
@@ -79,11 +79,11 @@ describe Deployable do
     catalog2 = FactoryGirl.create :catalog
     catalog1.pool.should_not == catalog2.pool
     admin = FactoryGirl.create :admin_user
-    pool1_perm = Permission.create(:user => admin,
+    pool1_perm = Permission.create(:entity => admin.entity,
                                    :role => Role.first(:conditions =>
                                                    ['name = ?', 'pool.admin']),
                                      :permission_object => catalog1.pool)
-    pool2_perm = Permission.create(:user => admin,
+    pool2_perm = Permission.create(:entity => admin.entity,
                                    :role => Role.first(:conditions =>
                                         ['name = ?', 'pool.deployable.admin']),
                                      :permission_object => catalog2.pool)
diff --git a/src/spec/models/deployment_spec.rb b/src/spec/models/deployment_spec.rb
index 7cf64f2..3ffbae9 100644
--- a/src/spec/models/deployment_spec.rb
+++ b/src/spec/models/deployment_spec.rb
@@ -219,13 +219,15 @@ describe Deployment do
       admin_perms = FactoryGirl.create :admin_permission
       @user_for_launch = admin_perms.user
       @user_for_launch.quota.maximum_running_instances = 1
+      @session = FactoryGirl.create :session
+      SessionEntity.update_session(@session, @user_for_launch)
       @deployment.stub(:common_provider_accounts_for).and_return(["test","test"])
     end
 
     it "return error when user quota was reached" do
       Instance.any_instance.stub(:matches).and_return(["test","test"])
       @deployment.stub!(:find_match_with_common_account).and_return([[], true, []])
-      errors = @deployment.check_assemblies_matches(@user_for_launch)
+      errors = @deployment.check_assemblies_matches(@session, @user_for_launch)
       errors.should have(1).items
       errors.last.should include I18n.t('instances.errors.user_quota_reached')
     end
@@ -243,19 +245,21 @@ describe Deployment do
       @deployment.pool.pool_family.provider_accounts = [@provider_account2, @provider_account1]
       admin_perms = FactoryGirl.create :admin_permission
       @user_for_launch = admin_perms.user
+      @session = FactoryGirl.create :session
+      SessionEntity.update_session(@session, @user_for_launch)
     end
 
     it "should return errors when checking assemblies matches which are not launchable" do
-      @deployment.check_assemblies_matches(@user_for_launch).should be_empty
+      @deployment.check_assemblies_matches(@session, @user_for_launch).should be_empty
       @deployment.pool.pool_family.provider_accounts.destroy_all
-      @deployment.check_assemblies_matches(@user_for_launch).should_not be_empty
+      @deployment.check_assemblies_matches(@session, @user_for_launch).should_not be_empty
     end
 
     it "should launch instances when launching deployment" do
       @deployment.instances.should be_empty
 
       Taskomatic.stub!(:create_instance!).and_return(true)
-      @deployment.create_and_launch(@user_for_launch)
+      @deployment.create_and_launch(@session, @user_for_launch)
       @deployment.errors.should be_empty
       @deployment.instances.count.should == 2
     end
@@ -268,7 +272,7 @@ describe Deployment do
       Taskomatic.stub!(:create_dcloud_instance).and_return(true)
       Taskomatic.stub!(:handle_dcloud_error).and_return(true)
       Taskomatic.stub!(:handle_instance_state).and_return(true)
-      @deployment.create_and_launch(@user_for_launch)
+      @deployment.create_and_launch(@session, @user_for_launch)
       @deployment.errors.should be_empty
       @deployment.reload
       @deployment.instances.count.should == 2
@@ -277,7 +281,7 @@ describe Deployment do
       @provider_account1.priority = 30
       @provider_account1.save!
       deployment2 = Factory.create(:deployment, :pool_id => @pool.id)
-      deployment2.create_and_launch(@user_for_launch)
+      deployment2.create_and_launch(@session, @user_for_launch)
       deployment2.errors.should be_empty
       deployment2.reload
       deployment2.instances.count.should == 2
@@ -296,7 +300,7 @@ describe Deployment do
       Taskomatic.stub!(:create_dcloud_instance).and_return(true)
       Taskomatic.stub!(:handle_dcloud_error).and_return(true)
       Taskomatic.stub!(:handle_instance_state).and_return(true)
-      @deployment.create_and_launch(@user_for_launch)
+      @deployment.create_and_launch(@session, @user_for_launch)
       @deployment.errors.should be_empty
       @deployment.reload
       @deployment.instances.count.should == 2
@@ -308,7 +312,7 @@ describe Deployment do
       @deployment.instances.should be_empty
       @deployment.pool.pool_family.provider_accounts.destroy_all
       Taskomatic.stub!(:create_instance!).and_return(true)
-      @deployment.create_and_launch(@user_for_launch)
+      @deployment.create_and_launch(@session, @user_for_launch)
       @deployment.errors.should_not be_empty
       lambda { Deployment.find(@deployment.id) }.should raise_error(ActiveRecord::RecordNotFound)
     end
@@ -321,7 +325,7 @@ describe Deployment do
       it "should set create_failed status for instances if instance's launch raises an exception" do
         @deployment.instances.should be_empty
         Taskomatic.stub!(:create_dcloud_instance).and_raise("an exception")
-        @deployment.create_and_launch(@user_for_launch)
+        @deployment.create_and_launch(@session, @user_for_launch)
         @deployment.reload
         @deployment.instances.should_not be_empty
         @deployment.instances.each {|i| i.state.should == Instance::STATE_CREATE_FAILED}
diff --git a/src/spec/models/derived_permission_spec.rb b/src/spec/models/derived_permission_spec.rb
new file mode 100644
index 0000000..9952330
--- /dev/null
+++ b/src/spec/models/derived_permission_spec.rb
@@ -0,0 +1,50 @@
+#
+#   Copyright 2011 Red Hat, Inc.
+#
+#   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.
+#
+
+require 'spec_helper'
+
+describe DerivedPermission do
+
+  before(:each) do
+    @admin_permission = FactoryGirl.create :admin_permission
+    @provider_admin_permission = FactoryGirl.create :provider_admin_permission
+    @pool_creator_permission = FactoryGirl.create :pool_creator_permission
+    @pool_user_permission = FactoryGirl.create :pool_user_permission
+
+    @admin = @admin_permission.user
+    @provider_admin = @provider_admin_permission.user
+    @pool_user = @pool_user_permission.user
+
+    @provider = @provider_admin_permission.provider
+    @pool = @pool_user_permission.pool
+    @instance = Factory.create(:instance, :pool_id => @pool.id)
+  end
+
+  it "derived permissions created for instance" do
+    derived_perms_count = @instance.derived_permissions.size
+    @pool_perm = Permission.create(:entity => @admin.entity,
+                                    :role => Role.first(:conditions =>
+                                               ['name = ?', 'pool.admin']),
+                                     :permission_object => @pool)
+    @instance.reload
+    inst_perm_sources = @instance.derived_permissions.collect {|p| p.permission}
+    inst_perm_sources.size.should == (derived_perms_count + 1)
+    inst_perm_sources.include?(@pool_user_permission).should be_true
+    inst_perm_sources.include?(@pool_perm).should be_true
+    instance2 = Factory.create(:instance, :pool_id => @pool.id)
+    instance2.derived_permissions.collect {|p| p.permission}.include?(@pool_perm).should be_true
+  end
+end
diff --git a/src/spec/models/permission_spec.rb b/src/spec/models/permission_spec.rb
index df13e3f..ce92bd6 100644
--- a/src/spec/models/permission_spec.rb
+++ b/src/spec/models/permission_spec.rb
@@ -31,44 +31,56 @@ describe Permission do
 
     @provider = @provider_admin_permission.provider
     @pool = @pool_user_permission.pool
+    @session = FactoryGirl.create :session
+    SessionEntity.update_session(@session, @admin)
+    SessionEntity.add_to_session(@session, @provider_admin)
+    SessionEntity.add_to_session(@session, @pool_user)
   end
 
   it "Admin should be able to create users" do
-    BasePermissionObject.general_permission_scope.has_privilege(@admin,
+    BasePermissionObject.general_permission_scope.has_privilege(@session,
+                                                                @admin,
                                                                 Privilege::CREATE,
                                                                 User).should be_true
   end
 
   it "Provider Admin should NOT be able to create users" do
-    BasePermissionObject.general_permission_scope.has_privilege(@provider_admin,
+    BasePermissionObject.general_permission_scope.has_privilege(@session,
+                                                                @provider_admin,
                                                                 Privilege::CREATE,
                                                                 User).should be_false
   end
 
   it "Pool User should NOT be able to create users" do
-    BasePermissionObject.general_permission_scope.has_privilege(@pool_user,
+    BasePermissionObject.general_permission_scope.has_privilege(@session,
+                                                                @pool_user,
                                                                 Privilege::CREATE,
                                                                 User).should be_false
   end
 
   it "Provider Admin should be able to edit provider" do
-    @provider.has_privilege(@provider_admin, Privilege::MODIFY).should be_true
+    @provider.has_privilege(@session, @provider_admin,
+                            Privilege::MODIFY).should be_true
   end
 
   it "Admin should be able to edit provider" do
-    @provider.has_privilege(@admin, Privilege::MODIFY).should be_true
+    @provider.has_privilege(@session, @admin, Privilege::MODIFY).should be_true
   end
 
   it "Pool User should NOT be able to edit provider" do
-    @provider.has_privilege(@pool_user, Privilege::MODIFY).should be_false
+    @provider.has_privilege(@session, @pool_user,
+                            Privilege::MODIFY).should be_false
   end
 
   it "Pool User should be able to create instances in @pool" do
-    @pool.has_privilege(@pool_user, Privilege::CREATE, Instance).should be_true
+    @pool.has_privilege(@session, @pool_user,
+                        Privilege::CREATE, Instance).should be_true
   end
 
   it "Pool User should NOT be able to create instances in another pool" do
-    FactoryGirl.create(:tpool).has_privilege(@pool_user, Privilege::CREATE, Instance).should be_false
+    FactoryGirl.create(:tpool).has_privilege(@session, @pool_user,
+                                             Privilege::CREATE, Instance).
+      should be_false
   end
 
 end
diff --git a/src/spec/services/registration_service_spec.rb b/src/spec/services/registration_service_spec.rb
index 51a8c25..b7c33cc 100644
--- a/src/spec/services/registration_service_spec.rb
+++ b/src/spec/services/registration_service_spec.rb
@@ -37,6 +37,8 @@ describe RegistrationService do
 
     it "should register a user with default pool/quota/role perms when default settings set" do
       @user = FactoryGirl.create :user
+      @session = FactoryGirl.create :session
+      SessionEntity.update_session(@session, @user)
       @pool = MetadataObject.lookup("self_service_default_pool")
       @role = MetadataObject.lookup("self_service_default_role")
       @quota = FactoryGirl.create :quota
@@ -45,7 +47,7 @@ describe RegistrationService do
       @registration_service = RegistrationService.new(@user)
       @registration_service.save
 
-      @pools = Pool.list_for_user(@user, Privilege::CREATE, Instance)
+      @pools = Pool.list_for_user(@session, @user, Privilege::CREATE, Instance)
       @pools.length.should == 1
       @pools[0].name.should == "Default"
 
diff --git a/src/spec/spec_helper.rb b/src/spec/spec_helper.rb
index 00cb1fd..372d7b7 100644
--- a/src/spec/spec_helper.rb
+++ b/src/spec/spec_helper.rb
@@ -56,6 +56,11 @@ def mock_warden(user)
                                        :authenticate! => user,
                                        :user => user,
                                        :raw_session => nil)
+  request.session_options[:id] = 'ee73441902cb9445483e498cb05dc398'
+  @session = ActiveRecord::SessionStore::Session.
+    find_by_session_id('ee73441902cb9445483e498cb05dc398')
+  @session = FactoryGirl.create :session unless @session
+  SessionEntity.update_session(@session, user) if user
 end
 
 RSpec.configure do |config|
-- 
1.7.6.5




More information about the aeolus-devel mailing list