1
0
Fork 0
mirror of https://github.com/fog/fog-aws.git synced 2022-11-09 13:50:52 -05:00

model IAM groups

This commit is contained in:
Josh Lane 2015-05-21 09:30:27 -07:00
parent 8908b6f6e7
commit e131f1266e
15 changed files with 361 additions and 67 deletions

View file

@ -85,14 +85,16 @@ module Fog
request :upload_signing_certificate
model_path 'fog/aws/models/iam'
model :user
collection :users
model :policy
collection :policies
model :access_key
collection :access_keys
model :group
collection :groups
model :policy
collection :policies
model :role
collection :roles
model :user
collection :users
class Mock
def self.data

View file

@ -0,0 +1,78 @@
module Fog
module AWS
class IAM
class Group < Fog::Model
identity :id, :aliases => 'GroupId'
attribute :arn, :aliases => 'Arn'
attribute :name, :aliases => 'GroupName'
attribute :path, :aliases => 'Path'
attribute :users, :aliases => 'Users', :type => :array
def add_user(user_or_name)
requires :name
user = if user_or_name.is_a?(Fog::AWS::IAM::User)
user_or_name
else
service.users.new(:id => user_or_name)
end
service.add_user_to_group(self.name, user.identity)
merge_attributes(:users => self.users + [user])
end
def attach(policy_arn)
requires :name
service.attach_group_policy(self.name, policy_arn)
end
def save
if !persisted?
requires :name
merge_attributes(
service.create_group(self.name, self.path).body["Group"]
)
else
params = {}
if self.name
params['NewGroupName'] = self.name
end
if self.path
params['NewPath'] = self.path
end
service.update_group(self.name, params)
true
end
end
def policies
requires :name
service.policies(:group_name => self.name)
end
def reload
requires :name
data = begin
collection.get(self.name)
rescue Excon::Errors::SocketError
nil
end
return unless data
merge_attributes(data.attributes)
self
end
end
end
end
end

View file

@ -0,0 +1,59 @@
require 'fog/aws/models/iam/group'
module Fog
module AWS
class IAM
class Groups < Fog::Collection
attribute :truncated, :aliases => 'IsTruncated', :type => :boolean
attribute :marker, :aliases => 'Marker'
attribute :username
model Fog::AWS::IAM::Group
def all(options = {})
merge_attributes(options)
data, records = if self.username
response = service.list_groups_for_user(self.username, options)
[response.body, response.body['GroupsForUser']]
else
response = service.list_groups(options)
[response.body, response.body['Groups']]
end
merge_attributes(data)
load(records)
end
def get(identity)
data = service.get_group(identity)
group = data.body['Group']
users = data.body['Users'].map { |u| service.users.new(u) }
new(group.merge(:users => users))
rescue Fog::AWS::IAM::NotFound
nil
end
def each
if !block_given?
self
else
subset = dup.all
subset.each { |f| yield f }
while subset.truncated
subset = subset.all('Marker' => subset.marker, 'MaxItems' => 1000)
subset.each { |f| yield f }
end
self
end
end
end
end
end
end

View file

@ -7,29 +7,57 @@ module Fog
model Fog::AWS::IAM::Policy
attribute :username
attribute :group_name
def all
requires :username
# AWS method get_user_policy only returns an array of policy names, this is kind of useless,
# that's why it has to loop through the list to get the details of each element. I don't like it because it makes this method slow
policy_names = service.list_user_policies(self.username).body['PolicyNames'] # it returns an array
policies = policy_names.map do |policy_name|
service.get_user_policy(policy_name, self.username).body['Policy']
end
requires_one :username, :group_name
policies = if self.username
all_by_user(self.username)
else
all_by_group(self.group_name)
end
load(policies) # data is an array of attribute hashes
end
def get(identity)
requires :username
requires_one :username, :group_name
data = service.get_user_policy(identity, self.username).body['Policy']
new(data) # data is an attribute hash
data = if self.username
service.get_user_policy(identity, self.username)
else
service.get_group_policy(identity, self.group_name)
end.body['Policy']
new(data)
rescue Fog::AWS::IAM::NotFound
nil
end
def new(attributes = {})
super({ :username => self.username }.merge!(attributes))
super(self.attributes.merge(attributes))
end
private
# AWS method get_user_policy and list_group_policies only returns an array of policy names, this is kind of useless,
# that's why it has to loop through the list to get the details of each element. I don't like it because it makes this method slow
def all_by_group(group_name)
response = service.list_group_policies(group_name)
response.body['PolicyNames'].map do |policy_name|
service.get_group_policy(policy_name, group_name).body['Policy']
end
end
def all_by_user(username)
response = service.list_user_policies(username)
response.body['PolicyNames'].map do |policy_name|
service.get_user_policy(policy_name, username).body['Policy']
end
end
end
end

View file

@ -6,12 +6,19 @@ module Fog
attribute :username, :aliases => 'UserName'
attribute :document, :aliases => 'PolicyDocument'
attr_accessor :group_name
def save
requires :id
requires :username
requires_one :username, :group_name
requires :document
data = service.put_user_policy(username, id, document).body
data = if username
service.put_user_policy(username, id, document).body
else
service.put_group_policy(group_name, id, document).body
end
merge_attributes(data)
true
end

View file

@ -3,33 +3,41 @@ module Fog
class IAM
class User < Fog::Model
identity :id, :aliases => 'UserName'
attribute :path, :aliases => 'Path'
attribute :arn, :aliases => 'Arn'
attribute :user_id, :aliases => 'UserId'
attribute :path, :aliases => 'Path'
attribute :arn, :aliases => 'Arn'
attribute :user_id, :aliases => 'UserId'
attribute :created_at, :aliases => 'CreateDate', :type => :time
def access_keys
requires :id
service.access_keys(:username => id)
end
def destroy
requires :id
service.delete_user(id)
true
end
def groups
service.groups(:username => self.identity)
end
def policies
requires :id
service.policies(:username => id)
end
def save
requires :id
data = service.create_user(id, path || '/').body['User']
merge_attributes(data)
true
end
def destroy
requires :id
service.delete_user(id)
true
end
def policies
requires :id
service.policies(:username => id)
end
def access_keys
requires :id
service.access_keys(:username => id)
end
end
end
end

View file

@ -1,8 +1,9 @@
require 'fog/aws/parsers/iam/policy_parser'
module Fog
module Parsers
module AWS
module IAM
require 'fog/aws/parsers/iam/policy_parser'
class ListManagedPolicies < Fog::Parsers::AWS::IAM::PolicyParser
def reset
super

View file

@ -13,10 +13,10 @@ module Fog
when 'Policies'
@stack << name
when 'Policy'
@role =fresh_policy
@policy = fresh_policy
when 'member'
if @stack.last == 'Policies'
@role = fresh_policy
@policy = fresh_policy
end
end
super

View file

@ -30,23 +30,22 @@ module Fog
class Mock
def add_user_to_group(group_name, user_name)
if data[:groups].key? group_name
if data[:users].key? user_name
unless data[:groups][group_name][:members].include?(user_name)
data[:groups][group_name][:members] << user_name
end
Excon::Response.new.tap do |response|
response.status = 200
response.body = { 'RequestId' => Fog::AWS::Mock.request_id }
end
else
raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.")
end
else
unless data[:groups].key?(group_name)
raise Fog::AWS::IAM::NotFound.new("The group with name #{group_name} cannot be found.")
end
unless data[:users].key?(user_name)
raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.")
end
unless data[:groups][group_name][:members].include?(user_name)
data[:groups][group_name][:members] << user_name
end
Excon::Response.new.tap do |response|
response.status = 200
response.body = { 'RequestId' => Fog::AWS::Mock.request_id }
end
end
end
end

View file

@ -20,10 +20,10 @@ module Fog
#
def attach_group_policy(group_name, policy_arn)
request(
'Action' => 'AttachGroupPolicy',
'GroupName' => group_name,
'PolicyArn' => policy_arn,
:parser => Fog::Parsers::AWS::IAM::Basic.new
'Action' => 'AttachGroupPolicy',
'GroupName' => group_name,
'PolicyArn' => policy_arn,
:parser => Fog::Parsers::AWS::IAM::Basic.new
)
end
end

View file

@ -45,9 +45,9 @@ module Fog
Excon::Response.new.tap do |response|
response.body = { 'Group' => {
'GroupId' => data[:groups][group_name][:group_id],
'Path' => data[:groups][group_name][:path],
'Path' => data[:groups][group_name][:path],
'GroupName' => group_name,
'Arn' => (data[:groups][group_name][:arn]).strip
'Arn' => (data[:groups][group_name][:arn]).strip
},
'Users' => data[:groups][group_name][:members].map { |user| get_user(user).body['User'] },
'RequestId' => Fog::AWS::Mock.request_id }

View file

@ -22,10 +22,10 @@ module Fog
#
def get_group_policy(policy_name, group_name)
request({
'Action' => 'GetGroupPolicy',
'PolicyName' => policy_name,
'GroupName' => group_name,
:parser => Fog::Parsers::AWS::IAM::GetGroupPolicy.new
'Action' => 'GetGroupPolicy',
'PolicyName' => policy_name,
'GroupName' => group_name,
:parser => Fog::Parsers::AWS::IAM::GetGroupPolicy.new
})
end
end

View file

@ -32,6 +32,22 @@ module Fog
}.merge!(options))
end
end
class Mock
def list_group_policies(group_name, options = {})
#FIXME: doesn't use options atm
if data[:groups].key? group_name
Excon::Response.new.tap do |response|
response.body = { 'PolicyNames' => data[:groups][group_name][:policies].keys,
'IsTruncated' => false,
'RequestId' => Fog::AWS::Mock.request_id }
response.status = 200
end
else
raise Fog::AWS::IAM::NotFound.new("The user with name #{user_name} cannot be found.")
end
end
end
end
end
end

View file

@ -26,12 +26,49 @@ module Fog
#
def update_group(group_name, options = {})
request({
'Action' => 'UpdateGroup',
'GroupName' => group_name,
:parser => Fog::Parsers::AWS::IAM::UpdateGroup.new
'Action' => 'UpdateGroup',
'GroupName' => group_name,
:parser => Fog::Parsers::AWS::IAM::UpdateGroup.new
}.merge!(options))
end
end
class Mock
def update_group(group_name, options = {})
raise Fog::AWS::IAM::NotFound.new(
"The user with name #{group_name} cannot be found."
) unless self.data[:groups].key?(group_name)
response = Excon::Response.new
group = self.data[:groups][group_name]
new_path = options['NewPath']
new_group_name = options['NewGroupName']
if new_path
unless new_path.match(/\A\/[a-zA-Z0-9]+\/\Z/)
raise Fog::AWS::IAM::ValidationError,
"The specified value for path is invalid. It must begin and end with / and contain only alphanumeric characters and/or / characters."
end
group[:path] = new_path
end
if new_group_name
self.data[:groups].delete(group_name)
self.data[:groups][new_group_name] = group
end
response.status = 200
response.body = {
'Group' => {},
'RequestId' => Fog::AWS::Mock.request_id
}
response
end
end
end
end
end

View file

@ -0,0 +1,59 @@
Shindo.tests("Fog::Compute[:iam] | groups", ['aws','iam']) do
service = Fog::AWS[:iam]
group_name = uniq_id('fog-test-group')
policy_name = uniq_id('fog-test-policy')
group = nil
document = {"Statement" => [{"Effect" => "Allow", "Action" => "*", "Resource" => "*"}]}
tests('#create').succeeds do
group = service.groups.create(:name => group_name)
group.name == group_name
end
tests('#all').succeeds do
service.groups.all.map(&:name).include?(group_name)
end
tests('update').succeeds do
new_path = group.path = "/newpath/"
group.save
group.reload.path == new_path
end
tests('group') do
policy = nil
tests('#policies', '#create') do
policy = group.policies.create(:id => policy_name, :document => document)
end
tests('#policies', '#get').succeeds do
group.policies.get(policy_name) != nil
end
tests('#policies', '#all').succeeds do
group.policies.all.map(&:id).include?(policy.id)
end
tests('#users', 'when none').succeeds do
group.users.empty?
end
user = nil
tests('#add_user').succeeds do
user = service.users.create(:id => 'fog-test')
group.add_user(user)
group.users.include?(user)
end
tests('#users').succeeds do
group.reload.users.map(&:identity).include?(user.identity)
end
end
end