socialcast 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in socialcast.gemspec
3
+ # add gem dependencies via *.gemspec file
4
4
  gemspec
data/Rakefile CHANGED
@@ -1,16 +1,6 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- require 'rake'
5
- require 'rake/testtask'
6
-
7
- Rake::TestTask.new(:test) do |test|
8
- test.libs << 'lib' << 'test'
9
- test.pattern = 'test/test_*.rb'
10
- end
11
-
12
- namespace :test do
13
- task :all => ['test']
14
- end
15
-
16
- task :default => 'test:all'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
6
+ task :default => :spec
data/config/ldap.yml CHANGED
@@ -36,6 +36,19 @@ mappings:
36
36
  # unique_identifier: samaccountname
37
37
 
38
38
 
39
+ # Map LDAP Group Memberships to Socialcast Permissions
40
+ permission_mappings:
41
+ # configure LDAP field for group memberships (ex: memberof, isMemberOf, etc)
42
+ attribute_name: memberof
43
+ account_types:
44
+ external: "cn=External,dc=example,dc=com"
45
+ roles:
46
+ tenant_admin: "cn=Admins,dc=example,dc=com"
47
+ sbi_admin: "cn=Admins,dc=example,dc=com"
48
+ reach_admin: "cn=Admins,dc=example,dc=com"
49
+ town_hall_admin: "cn=Admins,dc=example,dc=com"
50
+
51
+
39
52
  # general script options
40
53
  options:
41
54
  # cleanup the extracted ldap data file after run is complete
@@ -4,6 +4,7 @@ require 'rest_client'
4
4
  require 'highline'
5
5
  require 'socialcast'
6
6
  require 'socialcast/message'
7
+ require File.join(File.dirname(__FILE__), 'net_ldap_ext')
7
8
 
8
9
  require 'zlib'
9
10
  require 'logger'
@@ -86,14 +87,22 @@ module Socialcast
86
87
  return
87
88
  end
88
89
 
90
+ fail "Unable to load configuration file: #{config_file}" unless File.exist?(config_file)
91
+ say "Using configuration file: #{config_file}"
89
92
  config = YAML.load_file config_file
90
93
  required_mappings = %w{email first_name last_name}
94
+ mappings = config.fetch 'mappings', {}
91
95
  required_mappings.each do |field|
92
- unless config["mappings"].has_key? field
96
+ unless mappings.has_key? field
93
97
  fail "Missing required mapping: #{field}"
94
98
  end
95
99
  end
96
100
 
101
+ permission_mappings = config.fetch 'permission_mappings', {}
102
+ membership_attribute = permission_mappings.fetch 'attribute_name', 'memberof'
103
+ attributes = mappings.values
104
+ attributes << membership_attribute
105
+
97
106
  output_file = File.join Dir.pwd, options[:output]
98
107
  Zlib::GzipWriter.open(output_file) do |gz|
99
108
  xml = Builder::XmlMarkup.new(:target => gz, :indent => 1)
@@ -109,27 +118,44 @@ module Socialcast
109
118
  say "Connected"
110
119
  say "Searching..."
111
120
  count = 0
112
- ldap.search(:return_result => false, :filter => connection["filter"], :base => connection["basedn"]) do |entry|
113
- next if grab_value(entry[config["mappings"]["email"]]).blank? || (config["mappings"].has_key?("unique_identifier") && grab_value(entry[config["mappings"]["unique_identifier"]]).blank?)
121
+
122
+ ldap.search(:return_result => false, :filter => connection["filter"], :base => connection["basedn"], :attributes => attributes) do |entry|
123
+ next if entry.grab(mappings["email"]).blank? || (mappings.has_key?("unique_identifier") && entry.grab(mappings["unique_identifier"]).blank?)
124
+
114
125
  users.user do |user|
115
126
  primary_attributes = %w{unique_identifier first_name last_name employee_number}
116
127
  primary_attributes.each do |attribute|
117
- next unless config['mappings'].has_key?(attribute)
118
- user.tag! attribute, grab_value(entry[config["mappings"][attribute]])
128
+ next unless mappings.has_key?(attribute)
129
+ user.tag! attribute, entry.grab(mappings[attribute])
119
130
  end
131
+
120
132
  contact_attributes = %w{email location cell_phone office_phone}
121
133
  user.tag! 'contact-info' do |contact_info|
122
134
  contact_attributes.each do |attribute|
123
- next unless config['mappings'].has_key?(attribute)
124
- contact_info.tag! attribute, grab_value(entry[config["mappings"][attribute]])
135
+ next unless mappings.has_key?(attribute)
136
+ contact_info.tag! attribute, entry.grab(mappings[attribute])
125
137
  end
126
138
  end
127
- custom_attributes = config['mappings'].keys - (primary_attributes + contact_attributes)
139
+
140
+ custom_attributes = mappings.keys - (primary_attributes + contact_attributes)
128
141
  user.tag! 'custom-fields', :type => "array" do |custom_fields|
129
142
  custom_attributes.each do |attribute|
130
143
  custom_fields.tag! 'custom-field' do |custom_field|
131
- custom_field.id(attribute)
132
- custom_field.value(grab_value(entry[config["mappings"][attribute]]))
144
+ custom_field.id attribute
145
+ custom_field.label attribute
146
+ custom_field.value entry.grab(mappings[attribute])
147
+ end
148
+ end
149
+ end
150
+
151
+ memberships = entry[membership_attribute]
152
+ if memberships.include?(permission_mappings['account_types']['external'])
153
+ user.tag! 'account-type', 'external'
154
+ else
155
+ user.tag! 'account-type', 'member'
156
+ user.tag! 'roles', :type => 'array' do |roles|
157
+ permission_mappings['roles'].each_pair do |socialcast_role, ldap_role|
158
+ roles.role socialcast_role if entry[membership_attribute].include?(ldap_role)
133
159
  end
134
160
  end
135
161
  end
@@ -0,0 +1,10 @@
1
+ require 'net/ldap'
2
+
3
+ class Net::LDAP::Entry
4
+
5
+ # grab a *single* value of an attribute
6
+ # abstracts away ldap multivalue attributes
7
+ def grab(attribute)
8
+ Array.wrap(self[attribute]).compact.first
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Socialcast
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/lib/socialcast.rb CHANGED
@@ -20,7 +20,4 @@ module Socialcast
20
20
  raise 'Unknown Socialcast credentials. Run `socialcast authenticate` to initialize' unless File.exist?(credentials_file)
21
21
  YAML.load_file(credentials_file)
22
22
  end
23
- def grab_value(entry)
24
- entry.is_a?(Array) ? entry.first : entry
25
- end
26
23
  end
data/socialcast.gemspec CHANGED
@@ -14,12 +14,13 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.rubyforge_project = "socialcast"
16
16
 
17
- s.add_development_dependency "shoulda", ">= 0"
18
17
  s.add_runtime_dependency 'rest-client', '>= 1.4.0'
19
18
  s.add_runtime_dependency 'json', '>= 1.4.6'
20
19
  s.add_runtime_dependency 'thor', '>= 0.14.6'
21
20
  s.add_runtime_dependency 'highline', '>= 1.6.2'
22
21
  s.add_runtime_dependency 'scashin133-net-ldap', '>= 0.1.4'
22
+ s.add_runtime_dependency 'activeresource', '>= 2.3.11'
23
+ s.add_development_dependency "rspec", '>= 2.6.0'
23
24
 
24
25
  s.files = `git ls-files`.split("\n")
25
26
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socialcast::CLI do
4
+ describe '#provision' do
5
+ context 'with external group member' do
6
+ before do
7
+ @entry = Net::LDAP::Entry.new("dc=example,dc=com")
8
+ @entry[:mail] = 'ryan@example.com'
9
+ @entry[:isMemberOf] = 'cn=External,dc=example,dc=com'
10
+
11
+ Net::LDAP.any_instance.stub(:search).and_yield(@entry)
12
+
13
+ @result = ''
14
+ Zlib::GzipWriter.stub(:open).and_yield(@result)
15
+ File.stub(:open).with(/ldap.yml/).and_yield(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'ldap.yml')))
16
+ File.stub(:open).with(/users.xml.gz/, anything).and_yield(@result)
17
+ File.stub(:open).with(/credentials.yml/).and_yield(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml')))
18
+
19
+ RestClient::Resource.any_instance.stub(:post)
20
+
21
+ Socialcast::CLI.start ['provision', '-c', 'spec/fixtures/ldap.yml']
22
+ end
23
+ it 'sets account-type to external' do
24
+ @result.should =~ %r{<account-type>external</account-type>}
25
+ end
26
+ end
27
+
28
+ context 'with tenant_admin group member' do
29
+ before do
30
+ @entry = Net::LDAP::Entry.new("dc=example,dc=com")
31
+ @entry[:mail] = 'ryan@example.com'
32
+ @entry[:isMemberOf] = 'cn=Admins,dc=example,dc=com'
33
+
34
+ Net::LDAP.any_instance.stub(:search).and_yield(@entry)
35
+
36
+ @result = ''
37
+ Zlib::GzipWriter.stub(:open).and_yield(@result)
38
+ File.stub(:open).with(/ldap.yml/).and_yield(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'ldap.yml')))
39
+ File.stub(:open).with(/users.xml.gz/, anything).and_yield(@result)
40
+ File.stub(:open).with(/credentials.yml/).and_yield(File.read(File.join(File.dirname(__FILE__), 'fixtures', 'credentials.yml')))
41
+
42
+ RestClient::Resource.any_instance.stub(:post)
43
+
44
+ Socialcast::CLI.start ['provision', '-c', 'spec/fixtures/ldap.yml']
45
+ end
46
+ it 'sets account-type to member' do
47
+ @result.should =~ %r{<account-type>member</account-type>}
48
+ end
49
+ it 'adds tenant_admin role' do
50
+ @result.should =~ %r{<role>tenant_admin</role>}
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :user: ryan@socialcast.com
3
+ :password: foo
4
+ :domain: test.staging.socialcast.com
@@ -0,0 +1,53 @@
1
+ ---
2
+ # LDAP connections
3
+ connections:
4
+ example_connection_1:
5
+ username: "cn=Directory Manager"
6
+ password: "test"
7
+ host: localhost
8
+ port: 1389
9
+ basedn: "dc=example,dc=com"
10
+ filter: "(mail=*)"
11
+
12
+
13
+ # LDAP attribute mappings
14
+ mappings:
15
+ first_name: givenName
16
+ last_name: sn
17
+ email: mail
18
+ # only use employee_number if the email is unknown
19
+ # employee_number: emp_id
20
+ # only use unique_identifier if you do not wish to use email as the main user identification method
21
+ # unique_identifier: samaccountname
22
+
23
+
24
+ # Map LDAP Group Memberships to Socialcast Permissions
25
+ permission_mappings:
26
+ # configure LDAP field for group memberships (ex: memberof, isMemberOf, etc)
27
+ attribute_name: isMemberOf
28
+ account_types:
29
+ external: "cn=External,dc=example,dc=com"
30
+ roles:
31
+ tenant_admin: "cn=Admins,dc=example,dc=com"
32
+ sbi_admin: "cn=SbiAdmins,dc=example,dc=com"
33
+ reach_admin: "cn=ReachAdmins,dc=example,dc=com"
34
+ town_hall_admin: "cn=TownHallAdmins,dc=example,dc=com"
35
+
36
+
37
+ # general script options
38
+ options:
39
+ # cleanup the extracted ldap data file after run is complete
40
+ delete_users_file: false
41
+ # skip sending emails to newly activated users
42
+ skip_emails: true
43
+ # do not actually provision accounts
44
+ # useful during testing
45
+ test: true
46
+
47
+
48
+ # http options for connecting to Socialcast servers
49
+ http:
50
+ timeout: 660
51
+ # optional setting if script must connect to Socialcast server through a proxy
52
+ # proxy: "http://username:password@proxy.company.com:3128"
53
+
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec/mocks'
5
+ RSpec::Mocks::setup(Object.new)
6
+
7
+ require 'socialcast/cli'
8
+
9
+ RSpec.configure do |config|
10
+ config.mock_with :rspec
11
+
12
+ def capture_with_status(stream)
13
+ exit_status = 0
14
+ begin
15
+ stream = stream.to_s
16
+ eval "$#{stream} = StringIO.new"
17
+ begin
18
+ yield
19
+ rescue SystemExit => system_exit # catch any exit calls
20
+ exit_status = system_exit.status
21
+ end
22
+ result = eval("$#{stream}").string
23
+ ensure
24
+ eval("$#{stream} = #{stream.upcase}")
25
+ end
26
+ return result, exit_status
27
+ end
28
+
29
+ def remove_directories(*names)
30
+ project_dir = Pathname.new(Dir.pwd)
31
+ names.each do |name|
32
+ FileUtils.rm_rf(project_dir.join(name)) if FileTest.exists?(project_dir.join(name))
33
+ end
34
+ end
35
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: socialcast
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 1
10
+ version: 1.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Sonnek
@@ -16,26 +16,12 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-07-07 00:00:00 Z
19
+ date: 2011-07-13 00:00:00 Z
20
20
  dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: shoulda
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
33
- type: :development
34
- version_requirements: *id001
35
21
  - !ruby/object:Gem::Dependency
36
22
  name: rest-client
37
23
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
39
25
  none: false
40
26
  requirements:
41
27
  - - ">="
@@ -47,11 +33,11 @@ dependencies:
47
33
  - 0
48
34
  version: 1.4.0
49
35
  type: :runtime
50
- version_requirements: *id002
36
+ version_requirements: *id001
51
37
  - !ruby/object:Gem::Dependency
52
38
  name: json
53
39
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ requirement: &id002 !ruby/object:Gem::Requirement
55
41
  none: false
56
42
  requirements:
57
43
  - - ">="
@@ -63,11 +49,11 @@ dependencies:
63
49
  - 6
64
50
  version: 1.4.6
65
51
  type: :runtime
66
- version_requirements: *id003
52
+ version_requirements: *id002
67
53
  - !ruby/object:Gem::Dependency
68
54
  name: thor
69
55
  prerelease: false
70
- requirement: &id004 !ruby/object:Gem::Requirement
56
+ requirement: &id003 !ruby/object:Gem::Requirement
71
57
  none: false
72
58
  requirements:
73
59
  - - ">="
@@ -79,11 +65,11 @@ dependencies:
79
65
  - 6
80
66
  version: 0.14.6
81
67
  type: :runtime
82
- version_requirements: *id004
68
+ version_requirements: *id003
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: highline
85
71
  prerelease: false
86
- requirement: &id005 !ruby/object:Gem::Requirement
72
+ requirement: &id004 !ruby/object:Gem::Requirement
87
73
  none: false
88
74
  requirements:
89
75
  - - ">="
@@ -95,11 +81,11 @@ dependencies:
95
81
  - 2
96
82
  version: 1.6.2
97
83
  type: :runtime
98
- version_requirements: *id005
84
+ version_requirements: *id004
99
85
  - !ruby/object:Gem::Dependency
100
86
  name: scashin133-net-ldap
101
87
  prerelease: false
102
- requirement: &id006 !ruby/object:Gem::Requirement
88
+ requirement: &id005 !ruby/object:Gem::Requirement
103
89
  none: false
104
90
  requirements:
105
91
  - - ">="
@@ -111,7 +97,39 @@ dependencies:
111
97
  - 4
112
98
  version: 0.1.4
113
99
  type: :runtime
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: activeresource
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 21
110
+ segments:
111
+ - 2
112
+ - 3
113
+ - 11
114
+ version: 2.3.11
115
+ type: :runtime
114
116
  version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 23
126
+ segments:
127
+ - 2
128
+ - 6
129
+ - 0
130
+ version: 2.6.0
131
+ type: :development
132
+ version_requirements: *id007
115
133
  description: publish messages to your stream from a command line interface
116
134
  email:
117
135
  - ryan@socialcast.com
@@ -124,6 +142,7 @@ extra_rdoc_files: []
124
142
  files:
125
143
  - .document
126
144
  - .gitignore
145
+ - .rspec
127
146
  - CONTRIBUTORS.txt
128
147
  - Gemfile
129
148
  - LICENSE.txt
@@ -134,11 +153,13 @@ files:
134
153
  - lib/socialcast.rb
135
154
  - lib/socialcast/cli.rb
136
155
  - lib/socialcast/message.rb
156
+ - lib/socialcast/net_ldap_ext.rb
137
157
  - lib/socialcast/version.rb
138
158
  - socialcast.gemspec
139
- - test/commander_helper.rb
140
- - test/helper.rb
141
- - test/test_socialcast.rb
159
+ - spec/cli_spec.rb
160
+ - spec/fixtures/credentials.yml
161
+ - spec/fixtures/ldap.yml
162
+ - spec/spec_helper.rb
142
163
  homepage: http://github.com/wireframe/socialcast-command-line
143
164
  licenses: []
144
165
 
@@ -173,6 +194,7 @@ signing_key:
173
194
  specification_version: 3
174
195
  summary: command line interface to socialcast api
175
196
  test_files:
176
- - test/commander_helper.rb
177
- - test/helper.rb
178
- - test/test_socialcast.rb
197
+ - spec/cli_spec.rb
198
+ - spec/fixtures/credentials.yml
199
+ - spec/fixtures/ldap.yml
200
+ - spec/spec_helper.rb
@@ -1,54 +0,0 @@
1
- require 'commander/import'
2
-
3
- # require 'rubygems'
4
- # require 'commander/import'
5
- # require 'stringio'
6
- #
7
- # # Mock terminal IO streams so we can spec against them
8
- #
9
- # def mock_terminal
10
- # @input = StringIO.new
11
- # @output = StringIO.new
12
- # $terminal = HighLine.new @input, @output
13
- # end
14
- #
15
- # # Create test command for usage within several specs
16
- #
17
- # def create_test_command
18
- # command :test do |c|
19
- # c.syntax = "test [options] <file>"
20
- # c.description = "test description"
21
- # c.example "description", "command"
22
- # c.example "description 2", "command 2"
23
- # c.option '-v', "--verbose", "verbose description"
24
- # c.when_called do |args, options|
25
- # "test %s" % args.join
26
- # end
27
- # end
28
- # @command = command :test
29
- # end
30
- #
31
- # # Create a new command runner
32
- #
33
- # def new_command_runner *args, &block
34
- # Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(args)
35
- # program :name, 'test'
36
- # program :version, '1.2.3'
37
- # program :description, 'something'
38
- # create_test_command
39
- # yield if block
40
- # Commander::Runner.instance
41
- # end
42
- #
43
- # # Comply with how specs were previously written
44
- #
45
- # def command_runner
46
- # Commander::Runner.instance
47
- # end
48
- #
49
- # def run *args
50
- # new_command_runner *args do
51
- # program :formatter, Commander::HelpFormatter::Base
52
- # end.run!
53
- # @output.string
54
- # end
data/test/helper.rb DELETED
@@ -1,11 +0,0 @@
1
- require 'rubygems'
2
- require 'test/unit'
3
- require 'shoulda'
4
- require File.join(File.dirname(__FILE__), 'commander_helper')
5
-
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
- $LOAD_PATH.unshift(File.dirname(__FILE__))
8
- require 'socialcast'
9
-
10
- class Test::Unit::TestCase
11
- end
@@ -1,12 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'helper')
2
- load File.join(File.dirname(__FILE__), '..', 'bin', 'socialcast')
3
-
4
- class TestSocialcast < Test::Unit::TestCase
5
- context 'socialcast command' do
6
- setup do
7
- command(:share).run
8
- end
9
- should 'run' do
10
- end
11
- end
12
- end