socialcast 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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