dnc 0.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +1 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +12 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +20 -0
- data/dnc.gemspec +37 -0
- data/lib/dnc.rb +4 -0
- data/lib/dnc/array.rb +16 -0
- data/lib/dnc/dn.rb +209 -0
- data/lib/dnc/string.rb +33 -0
- data/lib/dnc/version.rb +3 -0
- data/spec/fixtures/common_dns.txt +12 -0
- data/spec/lib/dn_spec.rb +73 -0
- data/spec/lib/string_spec.rb +39 -0
- data/spec/spec_helper.rb +23 -0
- metadata +244 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 470a323d926d5b35cf824c6984227b59413b1293
|
4
|
+
data.tar.gz: cd95e84a643c70999b4114a8a9080a8c36aa4268
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e41dda0c97dc5cd0166137cba422eb498db1a2102e8e00fe2f83a20b1d477de4742f6682bb2eb7ced9c36a55e159a21ff6b977d7885d2b517471b730b38be6ad
|
7
|
+
data.tar.gz: a11f87306b43ecb1784ffab751962ee71857e87eeb9a53d43b0993ac9ca46a5dfcaba7b0dbfa1f62954abac2a6e4d03e1b351211acb320dc2f47b61b612c414f
|
checksums.yaml.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
�dw8��Il?��"k����D�>ʪ��C���fT�nf_������d���t��aH��b�}��S��+O*Ʒ���\yüAy�`8�j�EW�L]M+G*����
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
�t�{P-�� L��"��^q���T�2�+��4[�l
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Steven Haddox
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Distinguished Name (DN) Converter
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'dnc'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install dnc
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'dnc'
|
25
|
+
dn_string = 'CN=Some Valid, O=DN, OU=string'
|
26
|
+
dn = DN.new(dn_string: dn_string)
|
27
|
+
# Or:
|
28
|
+
dn_string.to_dn
|
29
|
+
# And:
|
30
|
+
dn_string.to_dn.to_s
|
31
|
+
```
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/[my-github-username]/dnc/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'coveralls/rake/task'
|
5
|
+
Coveralls::RakeTask.new
|
6
|
+
|
7
|
+
task default: [:spec, :rubocop, 'coveralls:push']
|
8
|
+
|
9
|
+
desc 'Run specs'
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
|
12
|
+
desc 'Run rubocop'
|
13
|
+
task :rubocop do
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Display TODOs, FIXMEs, and OPTIMIZEs'
|
18
|
+
task :notes do
|
19
|
+
system("grep -r 'OPTIMIZE:\\|FIXME:\\|TODO:' #{Dir.pwd}")
|
20
|
+
end
|
data/dnc.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dnc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dnc"
|
8
|
+
spec.version = Dnc::VERSION
|
9
|
+
spec.authors = ["Steven Haddox"]
|
10
|
+
spec.email = ["steven@haddox.us"]
|
11
|
+
spec.summary = %q{Distinguished Name Converter}
|
12
|
+
spec.description = %q{Convert multiple X509 DN strings into a consistent(ish) format.}
|
13
|
+
spec.homepage = "https://github.com/stevenhaddox/dnc"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 1.9.3'
|
22
|
+
spec.add_dependency 'logging', '~> 1.8'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'awesome_print', '~> 1.2'
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
+
spec.add_development_dependency 'coveralls', '~> 0.7'
|
27
|
+
spec.add_development_dependency 'rack', '~> 1.5'
|
28
|
+
spec.add_development_dependency 'rack-test', '~> 0.6'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_development_dependency 'rubocop', '~> 0.27'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
32
|
+
spec.add_development_dependency 'simplecov', '~> 0.9'
|
33
|
+
spec.add_development_dependency 'yard', '~> 0.8'
|
34
|
+
|
35
|
+
spec.cert_chain = ['certs/stevenhaddox.pem']
|
36
|
+
spec.signing_key = File.expand_path("~/.gem/certs/gem-private_key.pem") if $0 =~ /gem\z/
|
37
|
+
end
|
data/lib/dnc.rb
ADDED
data/lib/dnc/array.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#
|
2
|
+
# Extend the core Array class to include `.wrap`
|
3
|
+
#
|
4
|
+
class Array
|
5
|
+
|
6
|
+
# Duplication of Ruby on Rails Array#wrap method
|
7
|
+
def self.wrap(object)
|
8
|
+
if object.nil?
|
9
|
+
[]
|
10
|
+
elsif object.respond_to?(:to_ary)
|
11
|
+
object.to_ary || [object]
|
12
|
+
else
|
13
|
+
[object]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/dnc/dn.rb
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'logging'
|
2
|
+
|
3
|
+
# Custom exception for strings that can't be parsed as per RFC1779
|
4
|
+
class DnDelimiterUnparsableError < TypeError; end
|
5
|
+
# Custom exception for strings that can't be parsed as per RFC1779
|
6
|
+
class DnStringUnparsableError < TypeError; end
|
7
|
+
|
8
|
+
# Accepts various DN strings and returns a DN object
|
9
|
+
class DN
|
10
|
+
attr_accessor :original_dn, :dn_string, :delimiter,
|
11
|
+
:cn, :l, :st, :o, :ou, :c, :street, :dc
|
12
|
+
|
13
|
+
# Initialize the instance
|
14
|
+
#
|
15
|
+
# @param opts [Hash] Options hash for new DN instance attribute values
|
16
|
+
# @param opts[:dn_string] [String] The DN string you want to parse into a DN
|
17
|
+
# @param opts[:logger] User provided logger vs Rails / Logging default logger
|
18
|
+
def initialize(opts={})
|
19
|
+
@dn_string = opts[:dn_string]
|
20
|
+
@original_dn = dn_string
|
21
|
+
fail "dnc: dn_string parameter is **required**" if dn_string.nil?
|
22
|
+
@logger = opts[:logger].nil? ? logger : opts[:logger]
|
23
|
+
@delimiter = opts[:delimiter].nil? ? identify_delimiter : opts[:delimiter]
|
24
|
+
format_dn
|
25
|
+
end
|
26
|
+
|
27
|
+
# logger method to return Rails logger if defined, else logging logger
|
28
|
+
def logger
|
29
|
+
return @logger if @logger
|
30
|
+
logger = Logging.logger[self]
|
31
|
+
@logger ||= Kernel.const_defined?('Rails') ? Rails.logger : logger
|
32
|
+
end
|
33
|
+
|
34
|
+
# Split passed DN by identified delimiter
|
35
|
+
def split_by_delimiter
|
36
|
+
dn_string.split(delimiter).reject(&:empty?)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Convert DN object into a string
|
40
|
+
def to_s
|
41
|
+
return_string = ""
|
42
|
+
%w(cn dc l st ou o c street).each do |string_name|
|
43
|
+
unless self.send(string_name.to_sym).nil? || self.send(string_name.to_sym).empty?
|
44
|
+
return_string += "," unless return_string.empty?
|
45
|
+
return_string += self.send("#{string_name}_string".to_sym)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
return_string
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Orchestrates reformatting DN to expected element order for LDAP auth.
|
55
|
+
def format_dn
|
56
|
+
dn_string.upcase! # Upcase all DNs for consistency
|
57
|
+
format_dn_element_order unless dn_begins_properly?(dn_string)
|
58
|
+
parse_rdns_to_attrs
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parse @dn_string RDNs and assign them to DN attributes
|
63
|
+
def parse_rdns_to_attrs
|
64
|
+
split_by_delimiter.each do |rdn|
|
65
|
+
unless rdn.include?('+')
|
66
|
+
parse_top_level_rdn(rdn)
|
67
|
+
else
|
68
|
+
parse_nested_rdn(rdn)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_top_level_rdn(rdn)
|
76
|
+
rdn_array = rdn.split('=')
|
77
|
+
method = rdn_array[0].downcase.to_sym
|
78
|
+
value = rdn_array[1]
|
79
|
+
unless send(method).nil? || send(method).empty?
|
80
|
+
send("#{method}=", Array.wrap(send(method)))
|
81
|
+
send("#{method}").insert(0, value)
|
82
|
+
else
|
83
|
+
send("#{method}=", value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_nested_rdn(rdn)
|
88
|
+
rdn_keypairs = {}
|
89
|
+
rdn_array = rdn.split('+')
|
90
|
+
rdn_array.each do |string|
|
91
|
+
keypair = string.split('=')
|
92
|
+
rdn_keypairs[keypair[0].to_sym] = keypair[1]
|
93
|
+
end
|
94
|
+
|
95
|
+
send("#{rdn_keypairs.keys.first.downcase}=", rdn_keypairs)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Ensure order of DN elements is proper for CAS server with ',' delimiter
|
99
|
+
def format_dn_element_order
|
100
|
+
formatted_dn = split_by_delimiter.reverse.join(delimiter)
|
101
|
+
if dn_begins_properly?(formatted_dn)
|
102
|
+
dn_string = formatted_dn
|
103
|
+
|
104
|
+
else
|
105
|
+
fail("DN invalid format for LDAP authentication, DN:\r\n#{original_dn}")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Verify DN starts with 'CN='
|
110
|
+
def dn_begins_properly?(dn_str)
|
111
|
+
dn_str.nil? ? false : (dn_str.start_with?("CN=") || dn_str.start_with?("#{delimiter}CN="))
|
112
|
+
end
|
113
|
+
|
114
|
+
# Regex to match the DN delimiter by getting the 2nd key non-word predecessor
|
115
|
+
def delimiter_regexp
|
116
|
+
/\A.*=.*((([^\w\s\+\)\(])|([_]))\s?)\w+=.*\z/
|
117
|
+
end
|
118
|
+
|
119
|
+
# Identify and set the DN delimiter
|
120
|
+
def identify_delimiter
|
121
|
+
begin
|
122
|
+
logger.debug("DN.identify_delimeter: #{dn_string}")
|
123
|
+
delimiter_regexp.match(dn_string)[1]
|
124
|
+
rescue
|
125
|
+
fail DnDelimiterUnparsableError, "DN delimiter could not be identified
|
126
|
+
\r\nPlease ensure your string complies with RFC1779 formatting."
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def cn_string
|
131
|
+
dynamic_strings('cn', cn.class)
|
132
|
+
end
|
133
|
+
|
134
|
+
def l_string
|
135
|
+
dynamic_strings('l', l.class)
|
136
|
+
end
|
137
|
+
|
138
|
+
def st_string
|
139
|
+
dynamic_strings('st', st.class)
|
140
|
+
end
|
141
|
+
|
142
|
+
def o_string
|
143
|
+
dynamic_strings('o', o.class)
|
144
|
+
end
|
145
|
+
|
146
|
+
def ou_string
|
147
|
+
dynamic_strings('ou', ou.class)
|
148
|
+
end
|
149
|
+
|
150
|
+
def c_string
|
151
|
+
dynamic_strings('c', c.class)
|
152
|
+
end
|
153
|
+
|
154
|
+
def street_string
|
155
|
+
dynamic_strings('street', street.class)
|
156
|
+
end
|
157
|
+
|
158
|
+
def dc_string
|
159
|
+
dynamic_strings('dc', dc.class)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Identify which RDN string formatteer to call by value's class
|
163
|
+
def dynamic_strings(getter_method, value_class)
|
164
|
+
case value_class.to_s
|
165
|
+
when Array.to_s
|
166
|
+
dn_array_to_string(getter_method)
|
167
|
+
when Hash.to_s
|
168
|
+
dn_hash_to_string(getter_method)
|
169
|
+
when String.to_s
|
170
|
+
dn_string_to_string(getter_method)
|
171
|
+
else
|
172
|
+
logger.error "Invalid string accessor method class: #{value_class}"
|
173
|
+
fail "Invalid string accessor method class: #{value_class}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# NOTE:
|
178
|
+
# The following methods are a code smell, they handle formatting the values
|
179
|
+
# in DN attrs and converting them into a string format based upon their class
|
180
|
+
|
181
|
+
# Dynamically define a method to return DN array values as string format
|
182
|
+
def dn_array_to_string(getter_method)
|
183
|
+
return_string = ""
|
184
|
+
value = self.send(getter_method.to_sym)
|
185
|
+
value.each do |element|
|
186
|
+
return_string += "," unless return_string.empty?
|
187
|
+
return_string += "#{getter_method.to_s.upcase}=#{element}"
|
188
|
+
end
|
189
|
+
|
190
|
+
return_string
|
191
|
+
end
|
192
|
+
|
193
|
+
# Dynamically define a method to return DN hash values as string format
|
194
|
+
def dn_hash_to_string(getter_method)
|
195
|
+
return_string = ""
|
196
|
+
value = self.send(getter_method.to_sym)
|
197
|
+
value.each do |key, string|
|
198
|
+
return_string += "+" unless return_string.empty?
|
199
|
+
return_string += "#{key}=#{string}"
|
200
|
+
end
|
201
|
+
|
202
|
+
return_string
|
203
|
+
end
|
204
|
+
|
205
|
+
# Dynamically define a method to return DN string values as string format
|
206
|
+
def dn_string_to_string(getter_method)
|
207
|
+
"#{getter_method.to_s.upcase}=#{self.send(getter_method.to_sym)}"
|
208
|
+
end
|
209
|
+
end
|
data/lib/dnc/string.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'dnc'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Extend the core String class to include `.to_dn` && `.to_dn!`
|
5
|
+
#
|
6
|
+
class String
|
7
|
+
|
8
|
+
# Parses the string to return a DN object
|
9
|
+
# Returns nil if a DN instance cannot be created
|
10
|
+
def to_dn
|
11
|
+
begin
|
12
|
+
new_dn = DN.new(dn_string: self.to_s)
|
13
|
+
rescue StandardError
|
14
|
+
new_dn = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
new_dn
|
18
|
+
end
|
19
|
+
|
20
|
+
# Similar to {#to_dn}, but raises an error unless the string can be
|
21
|
+
# explicitly parsed to a DN instance
|
22
|
+
def to_dn!
|
23
|
+
begin
|
24
|
+
new_dn = DN.new(dn_string: self.to_s)
|
25
|
+
rescue StandardError
|
26
|
+
raise DnStringUnparsableError,
|
27
|
+
"Could not force conversion to DN:\n#{inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
new_dn
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/dnc/version.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
/C=US/O=RB/OU=DEV/OU=RAILS/OU=People/CN=Last First (initial)%CN=LAST FIRST (INITIAL),OU=PEOPLE,OU=RAILS,OU=DEV,O=RB,C=US
|
2
|
+
/CN=Smith John+initials=cpt/OU=People/OU=RAILS/OU=DEV/O=RB/C=GB%CN=SMITH JOHN+INITIALS=CPT,OU=DEV,OU=RAILS,OU=PEOPLE,O=RB,C=GB
|
3
|
+
CN=John Smith+email=jsmith@mayflower.org,O=ISODE Consortium,C=GB,O=ISODE Consortium%CN=JOHN SMITH+EMAIL=JSMITH@MAYFLOWER.ORG,O=ISODE CONSORTIUM,C=GB,O=ISODE CONSORTIUM
|
4
|
+
/C=GB/O=RB/OU=DEV/OU=RAILS/OU=People/CN=Smith John+initials=cpt%CN=SMITH JOHN+INITIALS=CPT,OU=PEOPLE,OU=RAILS,OU=DEV,O=RB,C=GB
|
5
|
+
/C=US/O=RB/OU=DEV/OU=JS/OU=People/CN=Last First M (initial)%CN=LAST FIRST M (INITIAL),OU=PEOPLE,OU=JS,OU=DEV,O=RB,C=US
|
6
|
+
CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, ST=California, C=US%CN=MARSHALL T. ROSE,O=DOVER BEACH CONSULTING,L=SANTA CLARA,ST=CALIFORNIA,C=US
|
7
|
+
CN=FTAM Service, CN=Bells, OU=Computer Science, O=University College London, C=GB%CN=FTAM SERVICE,CN=BELLS,OU=COMPUTER SCIENCE,O=UNIVERSITY COLLEGE LONDON,C=GB
|
8
|
+
CN=Markus Kuhn, O=University of Erlangen, C=DE%CN=MARKUS KUHN,O=UNIVERSITY OF ERLANGEN,C=DE
|
9
|
+
CN=Steve Kille, O=ISODE Consortium, C=DE%CN=STEVE KILLE,O=ISODE CONSORTIUM,C=DE
|
10
|
+
CN=Steve Kille,O=ISODE Consortium,C=GB%CN=STEVE KILLE,O=ISODE CONSORTIUM,C=GB
|
11
|
+
CN=C E B\sid=ceb\foo=bar, C=GB, O=foo%CN=C E B\sid=ceb\foo=bar,C=GB,O=FOO
|
12
|
+
C=UK, ST=England, L=London, O=LShift Ltd., OU=Development, CN=Lee Coomber/UID=123456%CN=LEE COOMBER/UID=123456,OU=DEVELOPMENT,O=LSHIFT LTD.,L=LONDON,ST=ENGLAND,C=UK
|
data/spec/lib/dn_spec.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DN do
|
4
|
+
let!(:raw_dn) { '/C=US/O=RB/OU=DEV/OU=JS/OU=People/CN=Last First M (initial)' }
|
5
|
+
let!(:dn_to_s) { 'CN=LAST FIRST M (INITIAL),OU=PEOPLE,OU=JS,OU=DEV,O=RB,C=US' }
|
6
|
+
let(:valid_subject) { DN.new(dn_string: raw_dn) }
|
7
|
+
let(:dn_elements) { ["C=US", "O=RB", "OU=DEV", "OU=JS", "OU=PEOPLE", "CN=LAST FIRST M (INITIAL)"] }
|
8
|
+
|
9
|
+
#
|
10
|
+
# Unit specs
|
11
|
+
#
|
12
|
+
describe "#new" do
|
13
|
+
it "should create a new DN object when valid" do
|
14
|
+
expect(valid_subject.class.to_s).to eq(DN.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should identify the most likely delimiter" do
|
18
|
+
expect(valid_subject.delimiter).to eq('/')
|
19
|
+
%w(, ; - _ : \\ % ^ ! & * @ # $).each do |delim|
|
20
|
+
custom_delim_subject = DN.new(dn_string: raw_dn.gsub('/',delim))
|
21
|
+
expect(custom_delim_subject.delimiter).to eq(delim)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should split on identified delimiter" do
|
26
|
+
expect(valid_subject.split_by_delimiter).to eq(dn_elements)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse each key value pair and assign an attribute" do
|
30
|
+
expect(valid_subject.c).to eq('US')
|
31
|
+
expect(valid_subject.o).to eq('RB')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return appropriate attrs as arrays" do
|
35
|
+
[:ou, :dc].each do |array_wrapped_el|
|
36
|
+
dn = DN.new(dn_string: '/C=US/O=RB/OU=DEV/OU=JS/OU=People/DC=example/DC=org/CN=Last First M (initial)')
|
37
|
+
expect(dn.dc).to eq(['ORG', 'EXAMPLE'])
|
38
|
+
expect(dn.ou).to eq(['PEOPLE', 'JS', 'DEV'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should handle multiple RDN key value pairs in the CN and return an array of elements" do
|
43
|
+
dn = DN.new(dn_string: '/C=US/O=RB/OU=DEV/OU=JS/OU=People/DC=example/DC=org/CN=Last First M (initial)+email=initial@example.org+office=home')
|
44
|
+
expect(dn.cn).to eq({CN: 'LAST FIRST M (INITIAL)', EMAIL: 'INITIAL@EXAMPLE.ORG', OFFICE: 'HOME'})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "validations" do
|
49
|
+
it "should require a parsable DN string" do
|
50
|
+
expect{ DN.new(dn_string: "") }.to raise_error(DnDelimiterUnparsableError)
|
51
|
+
expect{ DN.new(dn_string: "nope") }.to raise_error(DnDelimiterUnparsableError)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe ".to_s" do
|
56
|
+
it "should return a properly formatted string for CAS & RFC1779 use" do
|
57
|
+
dn = DN.new(dn_string: '/C=US/O=RB/OU=DEV/OU=JS/OU=People/DC=example/DC=org/CN=Last First M (initial)+email=initial@example.org+office=home')
|
58
|
+
dn_string = 'CN=LAST FIRST M (INITIAL)+EMAIL=INITIAL@EXAMPLE.ORG+OFFICE=HOME,DC=ORG,DC=EXAMPLE,OU=PEOPLE,OU=JS,OU=DEV,O=RB,C=US'
|
59
|
+
expect(dn.to_s).to eq(dn_string)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should parse common DN formats into DN objects" do
|
63
|
+
pending "Finish this"
|
64
|
+
File.readlines('spec/fixtures/common_dns.txt').each do |line|
|
65
|
+
dn_in = line.rstrip.split('%')[0]
|
66
|
+
dn_out = line.rstrip.split('%')[1]
|
67
|
+
#ap dn_in
|
68
|
+
#ap dn_out
|
69
|
+
expect(DN.new(dn_string: dn_in).to_s).to eq(dn_out)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe String do
|
4
|
+
let!(:raw_dn) { '/DC=org/DC=ruby-lang/CN=Ruby certificate rbcert' }
|
5
|
+
let(:dn) {
|
6
|
+
DN.new({
|
7
|
+
dn_string: raw_dn,
|
8
|
+
})
|
9
|
+
}
|
10
|
+
let(:dn_to_s) { 'CN=RUBY CERTIFICATE RBCERT,DC=RUBY-LANG,DC=ORG' }
|
11
|
+
|
12
|
+
after :all do
|
13
|
+
#expect(@log_output.readline).to eq("DEBUG String: DNC raw_dn:\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".to_dn" do
|
17
|
+
it "should return a DN instance if the string can be parsed" do
|
18
|
+
expect(raw_dn.to_dn.class.to_s).to eq('DN')
|
19
|
+
expect(raw_dn.to_dn.to_yaml).to eq(dn.to_yaml)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return nil otherwise" do
|
23
|
+
expect("".to_dn).to eql(nil)
|
24
|
+
expect("nope".to_dn).to eql(nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".to_dn!" do
|
29
|
+
it "should return a DN instance if the string can be parsed" do
|
30
|
+
expect(raw_dn.to_dn!.class.to_s).to eq('DN')
|
31
|
+
expect(raw_dn.to_dn!.to_yaml).to eq(dn.to_yaml)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should raise a DnStringUnparsableError otherwise" do
|
35
|
+
expect{ "".to_dn! }.to raise_error(DnStringUnparsableError)
|
36
|
+
expect{ "nope".to_dn! }.to raise_error(DnStringUnparsableError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
4
|
+
SimpleCov.start do
|
5
|
+
add_filter '/spec/'
|
6
|
+
end
|
7
|
+
# SimpleCov always comes before **anything** else
|
8
|
+
|
9
|
+
require_relative '../lib/dnc'
|
10
|
+
require 'awesome_print'
|
11
|
+
#require 'rspec/logging_helper'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.run_all_when_everything_filtered = true
|
15
|
+
config.filter_run :focus
|
16
|
+
config.filter_run_excluding :skip
|
17
|
+
config.order = 'random'
|
18
|
+
|
19
|
+
# Configure RSpec to capture log messages for each test. The output from the
|
20
|
+
# logs will be stored in the @log_output variable. It is a StringIO instance.
|
21
|
+
# include RSpec::LoggingHelper
|
22
|
+
# config.capture_log_messages
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dnc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Haddox
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDhTCCAm2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMRYwFAYDVQQDDA1zdGV2
|
14
|
+
ZW4uaGFkZG94MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
|
15
|
+
FgNjb20wHhcNMTQxMTE4MDIxMzIwWhcNMTUxMTE4MDIxMzIwWjBEMRYwFAYDVQQD
|
16
|
+
DA1zdGV2ZW4uaGFkZG94MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
|
17
|
+
k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDanmKr
|
18
|
+
vJDcVGMeDbDouLfKvU5ugOcHTXP04QDYSshaMTeuWSm4OXakxk2rxnR7Laq86R+8
|
19
|
+
h1NbHMdiZdwlHcpZm9/YD6qjbQhnLNGsezMrNpfZwfy9VnUQY4e0OCAca9vQXKTL
|
20
|
+
qC4fiuRD6sQQpyXkiIno0KlJOA4sKtH8vFucPGmhO0FUdlQY5FarDvCvZrtteO6L
|
21
|
+
6/GQFjupFBd9X6zt1XBs28IC+YUw33SN0UJ5JHB45ig0BmeWMXdd4SKWe4ve/2UY
|
22
|
+
asgs2miI3HP0wCPs0EF64/8LbuEUyMjHDr3a7+7KIRxYn2H/yUH5Ndqz6yL5G0sf
|
23
|
+
jUsC32JuE7VlJwFNAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAd
|
24
|
+
BgNVHQ4EFgQUC8HywyOMPJFCsH7uGW+CeKcZ8+8wIgYDVR0RBBswGYEXc3RldmVu
|
25
|
+
LmhhZGRveEBnbWFpbC5jb20wIgYDVR0SBBswGYEXc3RldmVuLmhhZGRveEBnbWFp
|
26
|
+
bC5jb20wDQYJKoZIhvcNAQEFBQADggEBAFoac9ZKc20ZXw2R2mWUz7FaJJdUvb7o
|
27
|
+
4rKVzFQkJwvAX+NEdP32yCDViGoEqlA13el5fllllmG3E7Qrw+0JA5B3wrZbVfQA
|
28
|
+
v4eX0ZohhW3CXLSz65pd3zfrwPAw0pXs1QKP+IioTuLQoBsGUiIqCPulZvzn/xN2
|
29
|
+
KG7SexyfUEXyJRMMigA/mE8h6bYfgKKUmLQVs1uRaXmOI7dKUF6HZJpda51zJH3v
|
30
|
+
42qdwEXvvkODZAD6KAIXPdmbMfBgPbcd+B/4eUA0PyKo+4dgL1NuqX4MPWToevIZ
|
31
|
+
O8EKLF2X7NmC6FY1bOsSj/J8r1SOkx0rxgF+geRvY1P+hfNjDfxTsjU=
|
32
|
+
-----END CERTIFICATE-----
|
33
|
+
date: 2015-01-13 00:00:00.000000000 Z
|
34
|
+
dependencies:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: logging
|
37
|
+
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.8'
|
42
|
+
type: :runtime
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.8'
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: awesome_print
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.2'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.2'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: bundler
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.6'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '1.6'
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: coveralls
|
79
|
+
requirement: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.7'
|
84
|
+
type: :development
|
85
|
+
prerelease: false
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0.7'
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rack
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.5'
|
98
|
+
type: :development
|
99
|
+
prerelease: false
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1.5'
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: rack-test
|
107
|
+
requirement: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.6'
|
112
|
+
type: :development
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0.6'
|
119
|
+
- !ruby/object:Gem::Dependency
|
120
|
+
name: rake
|
121
|
+
requirement: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '10.0'
|
126
|
+
type: :development
|
127
|
+
prerelease: false
|
128
|
+
version_requirements: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '10.0'
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: rubocop
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.27'
|
140
|
+
type: :development
|
141
|
+
prerelease: false
|
142
|
+
version_requirements: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0.27'
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: rspec
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '3.1'
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '3.1'
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: simplecov
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0.9'
|
168
|
+
type: :development
|
169
|
+
prerelease: false
|
170
|
+
version_requirements: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0.9'
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: yard
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "~>"
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0.8'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - "~>"
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0.8'
|
189
|
+
description: Convert multiple X509 DN strings into a consistent(ish) format.
|
190
|
+
email:
|
191
|
+
- steven@haddox.us
|
192
|
+
executables: []
|
193
|
+
extensions: []
|
194
|
+
extra_rdoc_files: []
|
195
|
+
files:
|
196
|
+
- ".coveralls.yml"
|
197
|
+
- ".gitignore"
|
198
|
+
- ".rubocop.yml"
|
199
|
+
- ".travis.yml"
|
200
|
+
- ".yardopts"
|
201
|
+
- Gemfile
|
202
|
+
- LICENSE.txt
|
203
|
+
- README.md
|
204
|
+
- Rakefile
|
205
|
+
- dnc.gemspec
|
206
|
+
- lib/dnc.rb
|
207
|
+
- lib/dnc/array.rb
|
208
|
+
- lib/dnc/dn.rb
|
209
|
+
- lib/dnc/string.rb
|
210
|
+
- lib/dnc/version.rb
|
211
|
+
- spec/fixtures/common_dns.txt
|
212
|
+
- spec/lib/dn_spec.rb
|
213
|
+
- spec/lib/string_spec.rb
|
214
|
+
- spec/spec_helper.rb
|
215
|
+
homepage: https://github.com/stevenhaddox/dnc
|
216
|
+
licenses:
|
217
|
+
- MIT
|
218
|
+
metadata: {}
|
219
|
+
post_install_message:
|
220
|
+
rdoc_options: []
|
221
|
+
require_paths:
|
222
|
+
- lib
|
223
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - ">="
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: 1.9.3
|
228
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
229
|
+
requirements:
|
230
|
+
- - ">="
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: '0'
|
233
|
+
requirements: []
|
234
|
+
rubyforge_project:
|
235
|
+
rubygems_version: 2.4.4
|
236
|
+
signing_key:
|
237
|
+
specification_version: 4
|
238
|
+
summary: Distinguished Name Converter
|
239
|
+
test_files:
|
240
|
+
- spec/fixtures/common_dns.txt
|
241
|
+
- spec/lib/dn_spec.rb
|
242
|
+
- spec/lib/string_spec.rb
|
243
|
+
- spec/spec_helper.rb
|
244
|
+
has_rdoc:
|
metadata.gz.sig
ADDED
Binary file
|