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

Merge pull request #959 from restebanez/feature/iam-improvement

[AWS|IAM] users, access_keys and policies models implemented
This commit is contained in:
Wesley Beary 2012-06-11 12:25:45 -07:00
commit f895aebd29
14 changed files with 441 additions and 4 deletions

View file

@ -55,6 +55,15 @@ module Fog
request :update_user
request :upload_server_certificate
request :upload_signing_certificate
model_path 'fog/aws/models/iam'
model :user
collection :users
model :policy
collection :policies
model :access_key
collection :access_keys
class Mock
def self.data

View file

@ -0,0 +1,38 @@
require 'fog/core/model'
module Fog
module AWS
class IAM
class AccessKey < Fog::Model
identity :id, :aliases => 'AccessKeyId'
attribute :username, :aliases => 'UserName'
attribute :secret_access_key, :aliases => 'SecretAccessKey'
attribute :status, :aliases => 'Status'
def save
requires :username
data = connection.create_access_key('UserName'=> username).body["AccessKey"]
merge_attributes(data)
true
end
def destroy
requires :id
requires :username
connection.delete_access_key(id,'UserName'=> username)
true
end
def user
requires :username
connection.users.get(username)
end
end
end
end
end

View file

@ -0,0 +1,36 @@
require 'fog/core/collection'
require 'fog/aws/models/iam/access_key'
module Fog
module AWS
class IAM
class AccessKeys < Fog::Collection
model Fog::AWS::IAM::AccessKey
def initialize(attributes = {})
@username = attributes[:username]
raise ArgumentError.new("Can't get an access_key's user without a username") unless @username
super
end
def all
data = connection.list_access_keys('UserName'=> @username).body['AccessKeys']
# AWS response doesn't contain the UserName, this injects it
data.each {|access_key| access_key['UserName'] = @username }
load(data)
end
def get(identity)
self.all.select {|access_key| access_key.id == identity}.first
end
def new(attributes = {})
super({ :username => @username }.merge!(attributes))
end
end
end
end
end

View file

@ -0,0 +1,44 @@
require 'fog/core/collection'
require 'fog/aws/models/iam/policy'
module Fog
module AWS
class IAM
class Policies < Fog::Collection
model Fog::AWS::IAM::Policy
def initialize(attributes = {})
@username = attributes[:username]
raise ArgumentError.new("Can't get a policy's user without a username") unless @username
super
end
def all
# 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 = connection.list_user_policies(@username).body['PolicyNames'] # it returns an array
policies = []
policy_names.each do |policy_name|
policies << connection.get_user_policy(policy_name,@username).body['Policy']
end
load(policies) # data is an array of attribute hashes
end
def get(identity)
data = connection.get_user_policy(identity,@username).body['Policy']
new(data) # data is an attribute hash
rescue Fog::AWS::IAM::NotFound
nil
end
def new(attributes = {})
super({ :username => @username }.merge!(attributes))
end
end
end
end
end

View file

@ -0,0 +1,39 @@
require 'fog/core/model'
module Fog
module AWS
class IAM
class Policy < Fog::Model
identity :id, :aliases => 'PolicyName'
attribute :username, :aliases => 'UserName'
attribute :document, :aliases => 'PolicyDocument'
def save
requires :id
requires :username
requires :document
data = connection.put_user_policy(username, id, document).body
merge_attributes(data)
true
end
def destroy
requires :id
requires :username
connection.delete_user_policy(username, id)
true
end
def user
requires :username
connection.users.get(username)
end
end
end
end
end

View file

@ -0,0 +1,40 @@
require 'fog/core/model'
module Fog
module AWS
class IAM
class User < Fog::Model
identity :id, :aliases => 'UserName'
attribute :path, :aliases => 'Path'
attribute :arn, :aliases => 'Arn'
attribute :user_id, :aliases => 'UserId'
def save
requires :id
data = connection.create_user(id).body['User']
merge_attributes(data)
true
end
def destroy
requires :id
connection.delete_user(id)
true
end
def policies
requires :id
connection.policies(:username => id)
end
def access_keys
requires :id
connection.access_keys(:username => id)
end
end
end
end
end

View file

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/aws/models/iam/user'
module Fog
module AWS
class IAM
class Users < Fog::Collection
model Fog::AWS::IAM::User
def all
data = connection.list_users.body['Users']
load(data) # data is an array of attribute hashes
end
def get(identity)
data = connection.get_user('UserName' => identity).body['User']
new(data) # data is an attribute hash
rescue Fog::AWS::IAM::NotFound
nil
end
end
end
end
end

View file

@ -7,13 +7,19 @@ module Fog
# http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUserPolicy.html
def reset
@response = {}
@response = { 'Policy' => {} }
end
def end_element(name)
case name
when 'UserName', 'PolicyName', 'PolicyDocument'
@response[name] = value
when 'UserName', 'PolicyName'
@response['Policy'][name] = value
when 'PolicyDocument'
@response['Policy'][name] = if decoded_string = URI.decode(value)
Fog::JSON.decode(decoded_string) rescue value
else
value
end
when 'RequestId'
@response[name] = value
end

View file

@ -78,7 +78,7 @@ module Fog
'BlockDeviceMappings' => [],
'CreatedTime' => Time.now.utc,
'ImageId' => image_id,
'InstanceMonitoring.Enabled' => true
'InstanceMonitoring.Enabled' => true,
'InstanceType' => instance_type,
'KernelId' => nil,
'KeyName' => nil,

View file

@ -31,6 +31,24 @@ module Fog
end
end
class Mock
def get_user(options = {})
user = options['UserName']
raise Fog::AWS::IAM::NotFound.new("The user with name #{user} cannot be found.") unless self.data[:users].key?(user)
Excon::Response.new.tap do |response|
response.body = {'User' => {
'UserId' => data[:users][user][:user_id],
'Path' => data[:users][user][:path],
'UserName' => user,
'Arn' => (data[:users][user][:arn]).strip
},
'IsTruncated' => false,
'RequestId' => Fog::AWS::Mock.request_id }
response.status = 200
end
end
end
end
end
end

View file

@ -31,6 +31,23 @@ module Fog
end
end
class Mock
def get_user_policy(policy_name, user_name)
raise Fog::AWS::IAM::NotFound.new("The user with name #{user} cannot be found.") unless self.data[:users].key?(user_name)
raise Fog::AWS::IAM::NotFound.new("The policy with name #{policy_name} cannot be found.") unless self.data[:users][user_name][:policies].key?(policy_name)
Excon::Response.new.tap do |response|
response.body = { 'Policy' => {
'PolicyName' => policy_name,
'UserName' => user_name,
'PolicyDocument' => data[:users][user_name][:policies][policy_name]
},
'IsTruncated' => false,
'RequestId' => Fog::AWS::Mock.request_id
}
response.status = 200
end
end
end
end
end
end

View file

@ -0,0 +1,53 @@
Shindo.tests("Fog::Compute[:iam] | access_keys", ['aws','iam']) do
Fog.mock!
iam = Fog::AWS[:iam]
@username = 'fake_user'
@user = iam.users.create(:id => @username)
tests('#all', 'there are no access keys for a new user').succeeds do
@user.access_keys.empty?
end
tests('#create','an access key').succeeds do
access_key = @user.access_keys.create
access_key.id =~ /[A-Z0-9]{20}/
access_key.secret_access_key =~ /[\S]{40}/
access_key.status == "Active"
access_key.username == @username
@access_key_id = access_key.id
end
@user.access_keys.create
tests('#all','there are two access keys').succeeds do
@user.access_keys.size == 2
end
tests('#get') do
tests('a valid access key id').succeeds do
access_key = @user.access_keys.get(@access_key_id)
access_key.id == @access_key_id
access_key.secret_access_key == nil
access_key.status == "Active"
access_key.username == @username
end
tests('an invalid access key').succeeds do
@user.access_keys.get('non-existing') == nil
end
end
tests('#destroy', 'decrease by one the number of access keys').succeeds do
size = @user.access_keys.size
@user.access_keys.get(@access_key_id).destroy
@user.access_keys.size == ( size - 1 )
end
# clean up
@user.destroy
end

View file

@ -0,0 +1,56 @@
Shindo.tests("Fog::Compute[:iam] | policies", ['aws','iam']) do
Fog.mock!
iam = Fog::AWS[:iam]
@username = 'fake_user'
@user = iam.users.create(:id => @username)
@policy_document = {"Statement"=>[{"Action"=>["sqs:*"], "Effect"=>"Allow", "Resource"=>"*"}]}
@policy_name = 'fake-sqs-policy'
tests('#all', 'there is no policies').succeeds do
@user.policies.empty?
end
tests('#create') do
tests('a valid policy').succeeds do
policy = @user.policies.create(id: @policy_name, document: @policy_document)
policy.id == @policy_name
policy.username == @username
policy.document == @policy_document
end
# The mocking doesn't validate the document policy
#tests('an invalid valid policy').succeeds do
# raises(Fog::AWS::IAM::Error) { @user.policies.create(id: 'non-valid-document', document: 'invalid json blob') }
#end
end
@user.policies.create(id: 'another-policy', document: {})
tests('#all','there are two policies').succeeds do
@user.policies.size == 2
end
tests('#get') do
tests('a valid policy').succeeds do
policy = @user.policies.get(@policy_name)
policy.id == @polic_name
policy.username == @username
policy.document == @policy_document
end
tests('an invalid policy').succeeds do
@user.policies.get('non-existing') == nil
end
end
tests('#destroy').succeeds do
@user.policies.get(@policy_name).destroy
end
# clean up
@user.destroy
end

View file

@ -0,0 +1,54 @@
Shindo.tests("Fog::Compute[:iam] | users", ['aws','iam']) do
Fog.mock!
@iam = Fog::AWS[:iam]
@user_one_name = 'fake_user_one'
@user_two_name = 'fake_user_two'
tests('#create').succeeds do
@user_one = @iam.users.create(:id => @user_one_name)
@user_one.id == @user_one_name
end
tests('#all','there is only one user').succeeds do
@iam.users.size == 1
end
tests('#all','the only user should match').succeeds do
@iam.users.first.id == @user_one_name
end
tests('#create','a second user').succeeds do
@user_two = @iam.users.create(:id => @user_two_name)
@user_two.id == @user_two_name
end
tests('#all','there are two users').succeeds do
@iam.users.size == 2
end
tests('#get','an existing user').succeeds do
@iam.users.get(@user_one_name).id == @user_one_name
end
tests('#get',"returns nil if the user doesn't exists").succeeds do
@iam.users.get('non-exists') == nil
end
tests('#policies','it has no policies').succeeds do
@iam.users.get(@user_one_name).policies.empty?
end
tests('#access_keys','it has no keys').succeeds do
@iam.users.get(@user_one_name).access_keys.empty?
end
tests('#destroy','an existing user').succeeds do
@iam.users.get(@user_one_name).destroy
end
tests('#destroy','clean up remaining user').succeeds do
@iam.users.get(@user_two_name).destroy
end
end