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:
commit
f895aebd29
14 changed files with 441 additions and 4 deletions
|
@ -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
|
||||
|
|
38
lib/fog/aws/models/iam/access_key.rb
Normal file
38
lib/fog/aws/models/iam/access_key.rb
Normal 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
|
36
lib/fog/aws/models/iam/access_keys.rb
Normal file
36
lib/fog/aws/models/iam/access_keys.rb
Normal 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
|
44
lib/fog/aws/models/iam/policies.rb
Normal file
44
lib/fog/aws/models/iam/policies.rb
Normal 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
|
39
lib/fog/aws/models/iam/policy.rb
Normal file
39
lib/fog/aws/models/iam/policy.rb
Normal 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
|
40
lib/fog/aws/models/iam/user.rb
Normal file
40
lib/fog/aws/models/iam/user.rb
Normal 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
|
27
lib/fog/aws/models/iam/users.rb
Normal file
27
lib/fog/aws/models/iam/users.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
53
tests/aws/models/iam/access_keys_tests.rb
Normal file
53
tests/aws/models/iam/access_keys_tests.rb
Normal 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
|
56
tests/aws/models/iam/policies_tests.rb
Normal file
56
tests/aws/models/iam/policies_tests.rb
Normal 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
|
54
tests/aws/models/iam/users_tests.rb
Normal file
54
tests/aws/models/iam/users_tests.rb
Normal 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
|
Loading…
Reference in a new issue