mdqt 0.1.1 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a4e1124b801ccc638cf0ffc2f8ce7f70321933f1a050506ce0ce3b39870b56b
4
- data.tar.gz: 7bebdb49dd714cf0f49c74dd31ec0505dd4957b408f781bf523c272262750496
3
+ metadata.gz: 1b4c3d3af10864847c7660c245d2ff0459ce87282011a7562ffa39c51c18f2f5
4
+ data.tar.gz: a1b470e3d206b7f5ed83f78afa970e13e7b1847ae96c5a1727b931c4a19846ec
5
5
  SHA512:
6
- metadata.gz: 9216f2cb673d91ca41ce2c029203527e5daa4aafa968d9a0645b62d28a000d52030417b02966b933986b6dd085c7a06217461d3b199cd310f53be1d9d6cbf930
7
- data.tar.gz: b594e5dba5098dfd0b5d6eb682a1d3196987888a5b48da2efe8707362439a34cf712f595afd949fe18816c46ff8d187e0144e3e340161c604030098c20e478cd
6
+ metadata.gz: 02fca67549a99277832129e8bf27344c9764c76519b464e57b8f28ddc5838f75d9cbd3e0adff603e9b2a57b985e7d93b61282a3b5d01e311f68f988cbdb64586
7
+ data.tar.gz: eed5827d3d9954211debb6bf52182777a01da7a8df266272bf338374c1bdd9f9ab54149d7cd5d86cf909ed645617d35791b0807814ed5c6823143d5cdb4a0554
data/.gitignore CHANGED
@@ -8,3 +8,6 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /out.xml
11
+ /out.txt
12
+ /mdqt_cache.log
13
+ *.gem
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
@@ -0,0 +1,296 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2018-05-03 07:42:59 +0100 using RuboCop version 0.55.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: Include, TreatCommentsAsGroupSeparators.
12
+ # Include: **/*.gemspec
13
+ Gemspec/OrderedDependencies:
14
+ Exclude:
15
+ - 'mdqt.gemspec'
16
+
17
+ # Offense count: 1
18
+ # Configuration parameters: Include.
19
+ # Include: **/*.gemspec
20
+ Gemspec/RequiredRubyVersion:
21
+ Exclude:
22
+ - 'mdqt.gemspec'
23
+
24
+ # Offense count: 1
25
+ # Cop supports --auto-correct.
26
+ Layout/CommentIndentation:
27
+ Exclude:
28
+ - 'lib/mdqt/cli/base.rb'
29
+
30
+ # Offense count: 1
31
+ # Cop supports --auto-correct.
32
+ # Configuration parameters: AllowBorderComment, AllowMarginComment.
33
+ Layout/EmptyComment:
34
+ Exclude:
35
+ - 'lib/mdqt/cli/base.rb'
36
+
37
+ # Offense count: 1
38
+ # Cop supports --auto-correct.
39
+ Layout/EmptyLineAfterMagicComment:
40
+ Exclude:
41
+ - 'mdqt.gemspec'
42
+
43
+ # Offense count: 3
44
+ # Cop supports --auto-correct.
45
+ Layout/EmptyLines:
46
+ Exclude:
47
+ - 'lib/mdqt/cli.rb'
48
+ - 'mdqt.gemspec'
49
+ - 'spec/client/client_spec.rb'
50
+
51
+ # Offense count: 3
52
+ # Cop supports --auto-correct.
53
+ # Configuration parameters: EnforcedStyle.
54
+ # SupportedStyles: empty_lines, no_empty_lines
55
+ Layout/EmptyLinesAroundBlockBody:
56
+ Exclude:
57
+ - 'exe/mdqt'
58
+ - 'spec/client/client_spec.rb'
59
+
60
+ # Offense count: 22
61
+ # Cop supports --auto-correct.
62
+ # Configuration parameters: EnforcedStyle.
63
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
64
+ Layout/EmptyLinesAroundClassBody:
65
+ Exclude:
66
+ - 'lib/mdqt/cli.rb'
67
+ - 'lib/mdqt/cli/base.rb'
68
+ - 'lib/mdqt/cli/defaults.rb'
69
+ - 'lib/mdqt/cli/get.rb'
70
+ - 'lib/mdqt/client.rb'
71
+ - 'lib/mdqt/client/metadata_service.rb'
72
+
73
+ # Offense count: 11
74
+ # Cop supports --auto-correct.
75
+ Layout/EmptyLinesAroundMethodBody:
76
+ Exclude:
77
+ - 'lib/mdqt/cli/base.rb'
78
+ - 'lib/mdqt/cli/get.rb'
79
+ - 'lib/mdqt/client.rb'
80
+ - 'lib/mdqt/client/metadata_service.rb'
81
+
82
+ # Offense count: 7
83
+ # Cop supports --auto-correct.
84
+ # Configuration parameters: EnforcedStyle.
85
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
86
+ Layout/EmptyLinesAroundModuleBody:
87
+ Exclude:
88
+ - 'lib/mdqt.rb'
89
+ - 'lib/mdqt/cli.rb'
90
+ - 'lib/mdqt/cli/base.rb'
91
+ - 'lib/mdqt/cli/get.rb'
92
+ - 'lib/mdqt/client.rb'
93
+ - 'lib/mdqt/client/metadata_service.rb'
94
+
95
+ # Offense count: 1
96
+ # Cop supports --auto-correct.
97
+ # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
98
+ Layout/ExtraSpacing:
99
+ Exclude:
100
+ - 'mdqt.gemspec'
101
+
102
+ # Offense count: 3
103
+ # Cop supports --auto-correct.
104
+ Layout/LeadingCommentSpace:
105
+ Exclude:
106
+ - 'exe/mdqt'
107
+ - 'lib/mdqt/client/metadata_service.rb'
108
+
109
+ # Offense count: 1
110
+ # Cop supports --auto-correct.
111
+ Layout/SpaceAfterComma:
112
+ Exclude:
113
+ - 'lib/mdqt/client/metadata_service.rb'
114
+
115
+ # Offense count: 1
116
+ # Cop supports --auto-correct.
117
+ # Configuration parameters: .
118
+ # SupportedStyles: space, no_space
119
+ Layout/SpaceAroundEqualsInParameterDefault:
120
+ EnforcedStyle: no_space
121
+
122
+ # Offense count: 1
123
+ # Cop supports --auto-correct.
124
+ # Configuration parameters: AllowForAlignment.
125
+ Layout/SpaceAroundOperators:
126
+ Exclude:
127
+ - 'mdqt.gemspec'
128
+
129
+ # Offense count: 1
130
+ # Cop supports --auto-correct.
131
+ # Configuration parameters: AllowForAlignment.
132
+ Layout/SpaceBeforeFirstArg:
133
+ Exclude:
134
+ - 'lib/mdqt/client/metadata_service.rb'
135
+
136
+ # Offense count: 2
137
+ # Cop supports --auto-correct.
138
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
139
+ # SupportedStyles: space, no_space
140
+ # SupportedStylesForEmptyBraces: space, no_space
141
+ Layout/SpaceInsideBlockBraces:
142
+ Exclude:
143
+ - 'lib/mdqt/cli/get.rb'
144
+
145
+ # Offense count: 7
146
+ # Cop supports --auto-correct.
147
+ # Configuration parameters: EnforcedStyle.
148
+ # SupportedStyles: final_newline, final_blank_line
149
+ Layout/TrailingBlankLines:
150
+ Exclude:
151
+ - 'exe/mdqt'
152
+ - 'lib/mdqt/cli.rb'
153
+ - 'lib/mdqt/cli/base.rb'
154
+ - 'lib/mdqt/cli/defaults.rb'
155
+ - 'lib/mdqt/client.rb'
156
+ - 'lib/mdqt/client/metadata_service.rb'
157
+ - 'spec/client/client_spec.rb'
158
+
159
+ # Offense count: 2
160
+ # Cop supports --auto-correct.
161
+ # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
162
+ Lint/UnusedBlockArgument:
163
+ Exclude:
164
+ - 'exe/mdqt'
165
+
166
+ # Offense count: 2
167
+ # Cop supports --auto-correct.
168
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
169
+ Lint/UnusedMethodArgument:
170
+ Exclude:
171
+ - 'lib/mdqt/cli/base.rb'
172
+
173
+ # Offense count: 1
174
+ Lint/UselessAssignment:
175
+ Exclude:
176
+ - 'lib/mdqt/client.rb'
177
+
178
+ # Offense count: 1
179
+ # Configuration parameters: CountComments.
180
+ Metrics/MethodLength:
181
+ Max: 13
182
+
183
+ # Offense count: 8
184
+ Style/Documentation:
185
+ Exclude:
186
+ - 'spec/**/*'
187
+ - 'test/**/*'
188
+ - 'lib/mdqt.rb'
189
+ - 'lib/mdqt/cli.rb'
190
+ - 'lib/mdqt/cli/base.rb'
191
+ - 'lib/mdqt/cli/defaults.rb'
192
+ - 'lib/mdqt/cli/get.rb'
193
+ - 'lib/mdqt/client.rb'
194
+ - 'lib/mdqt/client/metadata_service.rb'
195
+
196
+ # Offense count: 1
197
+ # Cop supports --auto-correct.
198
+ Style/Encoding:
199
+ Exclude:
200
+ - 'mdqt.gemspec'
201
+
202
+ # Offense count: 2
203
+ # Cop supports --auto-correct.
204
+ Style/ExpandPathArguments:
205
+ Exclude:
206
+ - 'mdqt.gemspec'
207
+ - 'spec/spec_helper.rb'
208
+
209
+ # Offense count: 16
210
+ # Cop supports --auto-correct.
211
+ # Configuration parameters: EnforcedStyle.
212
+ # SupportedStyles: when_needed, always, never
213
+ Style/FrozenStringLiteralComment:
214
+ Enabled: false
215
+
216
+ # Offense count: 2
217
+ # Cop supports --auto-correct.
218
+ # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
219
+ # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
220
+ Style/HashSyntax:
221
+ Exclude:
222
+ - 'Rakefile'
223
+ - 'lib/mdqt/client/metadata_service.rb'
224
+
225
+ # Offense count: 1
226
+ # Cop supports --auto-correct.
227
+ Style/MutableConstant:
228
+ Exclude:
229
+ - 'lib/mdqt/version.rb'
230
+
231
+ # Offense count: 1
232
+ # Cop supports --auto-correct.
233
+ # Configuration parameters: Whitelist.
234
+ # Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with
235
+ Style/NestedParenthesizedCalls:
236
+ Exclude:
237
+ - 'lib/mdqt/client/metadata_service.rb'
238
+
239
+ # Offense count: 2
240
+ # Cop supports --auto-correct.
241
+ # Configuration parameters: PreferredDelimiters.
242
+ Style/PercentLiteralDelimiters:
243
+ Exclude:
244
+ - 'mdqt.gemspec'
245
+
246
+ # Offense count: 1
247
+ # Cop supports --auto-correct.
248
+ Style/RedundantSelf:
249
+ Exclude:
250
+ - 'lib/mdqt/cli/base.rb'
251
+
252
+ # Offense count: 37
253
+ # Cop supports --auto-correct.
254
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
255
+ # SupportedStyles: single_quotes, double_quotes
256
+ Style/StringLiterals:
257
+ Exclude:
258
+ - 'Rakefile'
259
+ - 'bin/console'
260
+ - 'lib/mdqt.rb'
261
+ - 'lib/mdqt/cli/base.rb'
262
+ - 'lib/mdqt/cli/get.rb'
263
+ - 'lib/mdqt/client/metadata_service.rb'
264
+ - 'lib/mdqt/version.rb'
265
+ - 'mdqt.gemspec'
266
+ - 'spec/mdqt_spec.rb'
267
+ - 'spec/spec_helper.rb'
268
+
269
+ # Offense count: 1
270
+ # Cop supports --auto-correct.
271
+ # Configuration parameters: EnforcedStyleForMultiline.
272
+ # SupportedStylesForMultiline: comma, consistent_comma, no_comma
273
+ Style/TrailingCommaInHashLiteral:
274
+ Exclude:
275
+ - 'lib/mdqt/cli/defaults.rb'
276
+
277
+ # Offense count: 3
278
+ # Cop supports --auto-correct.
279
+ # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
280
+ # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
281
+ Style/TrivialAccessors:
282
+ Exclude:
283
+ - 'lib/mdqt/client.rb'
284
+ - 'lib/mdqt/client/metadata_service.rb'
285
+
286
+ # Offense count: 2
287
+ # Cop supports --auto-correct.
288
+ Style/UnneededPercentQ:
289
+ Exclude:
290
+ - 'mdqt.gemspec'
291
+
292
+ # Offense count: 7
293
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
294
+ # URISchemes: http, https
295
+ Metrics/LineLength:
296
+ Max: 130
@@ -1,5 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1.2
5
- before_install: gem install bundler -v 1.13.5
4
+ - 2.2.2
5
+ - 2.5.0
6
+ - jruby
7
+ before_install: gem install bundler -v 1.16.1
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ ### Improvements
6
+ - Option to cache HTTP requests to the MDQ service
7
+ - Supports Gzip compression by default
8
+ - Supports redirect responses
9
+ - Helpful error messages and status messages
10
+ - Verbose mode will show successful connection information
11
+ - Warnings about unspecified MDQ service
12
+ - Default MDQ service selection (rather crude, maybe not a good idea at all)
13
+ - Catch bad URLs for the MDQ service and fail with a better error message
14
+
15
+ ### Fixes
16
+ - Aggregates are now requested with /entities not /entities/, as per spec
17
+
18
+ ### Other
19
+ - First few Cucumber features to define and test the executable
20
+ - Beginning of an RSpec suit to define the API
21
+ - Minimum version of Ruby is now 2.1, but only 2.2+ is tested using CI
22
+
23
+ ## 0.1.1
24
+
25
+ ### Fixes
26
+ - Bug that prevented the mdqt executable from running outside a Bundler environment
27
+
28
+ ## 0.1.0
29
+
30
+ - Initial release
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in mdq.gemspec
4
4
  gemspec
5
+
6
+ gem 'simplecov', require: false, group: :test
data/README.md CHANGED
@@ -1,23 +1,31 @@
1
1
  # MDQT - A Metadata Query Tool
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/mdqt.svg)](https://badge.fury.io/rb/mdqt) [![Maintainability](https://api.codeclimate.com/v1/badges/111c46aaebfe25e4a4a9/maintainability)](https://codeclimate.com/github/Digital-Identity-Labs/mdqt/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/111c46aaebfe25e4a4a9/test_coverage)](https://codeclimate.com/github/Digital-Identity-Labs/mdqt/test_coverage) [![Build Status](https://travis-ci.org/Digital-Identity-Labs/mdqt.svg?branch=master)](https://travis-ci.org/Digital-Identity-Labs/mdqt)
4
+
3
5
  MDQT is small library and commandline tool to query MDQ services for SAML metadata.
4
- You can do this with `curl` but it's a little more convenient to use `mdqt` instead.
6
+ You could do this with `curl` but it's a little more convenient to use `mdqt` instead.
5
7
 
6
8
  At present `mdqt` does *not* verify signed metadata, so an extra step is required to use it
7
- securely. It is also not yet fully compliant with the MDQ client specification.
9
+ securely.
10
+
11
+ MDQ currently supports:
12
+
13
+ - Downloading single entities, lists or aggregates
14
+ - Caching entity metadata on disk
15
+ - Gzip compression
8
16
 
9
17
  ## MDQ?
10
18
 
11
19
  MDQ is a simple HTTP-based standard for looking up individual SAML entity metadata. Rather than regularly
12
20
  downloading large metadata aggregates containing thousands of entity descriptions,
13
- an IdP or SP can download the metadata for individual entities using MDQ when they are needed.
21
+ an IdP or SP can download the metadata for an individual entity whenever it is needed.
14
22
 
15
23
  The UK Access Management Federation has a
16
24
  [useful page explaining MDQ](https://www.ukfederation.org.uk/content/Documents/MDQ)
17
25
 
18
26
  ## Installation
19
27
 
20
- To add mdqt to a project, add this line to your application's Gemfile
28
+ To add MDQT to a project, include this line in your application's Gemfile
21
29
 
22
30
  ```ruby
23
31
  gem 'mdqt'
@@ -35,33 +43,47 @@ If using a per-user Ruby such via `rbenv` or similar, you'll just need
35
43
 
36
44
  $ gem install mdqt
37
45
 
46
+ MDQT should work with Ruby 2.1.0 or later.
47
+
38
48
  ## Commandline Usage as an MDQ client
39
49
 
40
- You can see a list of commandline options by typing
50
+ You can see a list of commandline options by typing:
41
51
 
42
52
  $ mdqt --help
43
53
 
44
- Specifying the MDQ service with a commandline option
54
+ To see more information about a command, use the `--help` option after the command:
55
+
56
+ $ mdqt get --help
57
+
58
+ Specifying the MDQ service with a commandline option:
45
59
 
46
60
  $ mdqt get --service https://mdq.example.com/mdq http://entity.ac.uk/shibboleth
47
61
 
48
62
  It's more convenient to set an environment variable to specify a default MDQ
49
- service. Set MDQT_SERVICE or MDQ_BASE_URL to the base URL of your MDQ service.
63
+ service. Set `MDQT_SERVICE` or `MDQ_BASE_URL` to the base URL of your MDQ service.
50
64
 
51
- Downloading entity metadata to STDOUT
65
+ Downloading entity metadata to STDOUT:
52
66
 
53
67
  $ mdqt get https://test-idp.ukfederation.org.uk/idp/shibboleth
54
68
 
55
- Using sha1 hashed version of entity IDs requires quotes or escaping
69
+ Using the sha1 hashed version of entity IDs requires quotes or escaping:
56
70
 
57
71
  $ mdqt get "{sha1}52e2065fc0d53744e8d4ee2c2f30696ebfc5def9"
58
72
 
59
73
  $ mdqt get \{sha1\}52e2065fc0d53744e8d4ee2c2f30696ebfc5def9
60
74
 
61
- Requesting all metadata from an MDQ endpoint is done by specifying `--all`
75
+ Requesting all metadata from an MDQ endpoint is done by specifying `--all`:
62
76
 
63
77
  $ mdqt get --all
64
78
 
79
+ Caching can be enabled using `--cache`. At the moment the `mdqt` executable
80
+ only supports caching to disk. It will create a cache directory in your temporary
81
+ directory.
82
+
83
+ $ mdqt get --cache --service https://mdq.example.com/mdq http://entity.ac.uk/shibboleth
84
+
85
+ If you don't specify an MDQ service with `--service' or `MDQT_SERVICE` then `mdqt` *might* be
86
+ able to guess your local NREN's MDQ service. Do not do this in production.
65
87
 
66
88
  ## Library Usage
67
89
 
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
2
 
4
- RSpec::Core::RakeTask.new(:spec)
3
+ Dir.glob('lib/tasks/*.rake').each { |r| load r}
5
4
 
6
- task :default => :spec
5
+ task :default => :tests
data/exe/mdqt CHANGED
@@ -23,14 +23,16 @@ Commander.configure do
23
23
  end
24
24
 
25
25
  command :get do |c|
26
- c.syntax = 'mdqt get [options] [entity id] [entity id] '
26
+ c.syntax = 'mdqt get [options] entityidentifier '
27
27
  c.description = 'Download one entity record or an aggregate of entity records'
28
28
  c.option '--service URL', String, 'MDQ service to search for entities. Defaults to MDQT_SERVICE or MDQ_BASE_URL env variables'
29
+ c.option '--cache', "Cache downloads and try to fetch from cache where appropriate"
29
30
  #c.option '--verify-with PATH', String, 'Validate downloads using specified certificate'
30
31
  #c.option '--stdin', 'accept one or more entity ids from STDIN'
31
32
  c.option '--all', 'Request all entity records'
32
33
  c.action do |args, options|
33
34
  options.default MDQT::CLI::Defaults.cli_defaults
35
+ options.default({service: MDQT::CLI::Defaults.base_url }) if options.service.nil?
34
36
  MDQT::CLI::Get.run(args, options)
35
37
  end
36
38
  end
@@ -5,12 +5,75 @@ module MDQT
5
5
  class Base
6
6
 
7
7
  def self.run(args, options)
8
- self.new.run(args, options)
8
+
9
+ #args = options.stdin ? absorb_piped_args(args) : args
10
+
11
+ check_requirements(args, options)
12
+ introduce(args, options)
13
+
14
+ self.new(args, options).run
15
+ end
16
+
17
+ def self.check_requirements(args, options)
18
+ abort "Error: No MDQ service URL has been specified." unless options.service
19
+ end
20
+
21
+ def self.introduce(args, options)
22
+ if options.verbose
23
+ STDERR.puts "Using #{options.service}"
24
+ STDERR.puts "Caching is #{options.service ? 'on' : 'off'}"
25
+ STDERR.puts
26
+ end
27
+ end
28
+
29
+ def self.absorb_piped_args(args)
30
+ piped = piped? ? parse_stdin : []
31
+ args + piped
32
+ end
33
+
34
+ def self.piped?
35
+ !STDIN.tty? && !STDIN.closed?
36
+ end
37
+
38
+ def self.parse_stdin
39
+ STDIN.gsub("\s", "\n").each_line.collect {|l| l.strip }
40
+ end
41
+
42
+ def initialize(args, options)
43
+ @args = args
44
+ @options = options
45
+ end
46
+
47
+ def args=(new_args)
48
+ @args = new_args
49
+ end
50
+
51
+ def args
52
+ @args
53
+ end
54
+
55
+ def options=(new_options)
56
+ @options = new_options
57
+ end
58
+
59
+ def options
60
+ @options
61
+ end
62
+
63
+ def output(response)
64
+ if response.ok?
65
+ STDERR.puts response.message if options.verbose
66
+ trailer = response.data[-1] == "\n" ? "" : "\n"
67
+ response.data + trailer
68
+ else
69
+ STDERR.puts response.message
70
+ end
71
+
9
72
  end
10
73
 
11
- def run(args, options)
74
+ def run
12
75
 
13
- puts "No action has been defined for this command!"
76
+ abort "No action has been defined for this command!"
14
77
 
15
78
  end
16
79
 
File without changes
File without changes
@@ -6,7 +6,7 @@ module MDQT
6
6
  class << self
7
7
 
8
8
  def base_url
9
- ENV['MDQT_SERVICE'] || ENV['MDQ_BASE_URL'] || 'http://mdq.ukfederation.org.uk/'
9
+ ENV['MDQT_SERVICE'] || ENV['MDQ_BASE_URL'] || guess_service
10
10
  end
11
11
 
12
12
  def force_hash?
@@ -15,11 +15,32 @@ module MDQT
15
15
 
16
16
  def cli_defaults
17
17
  {
18
- service: base_url,
19
18
  hash: force_hash?,
19
+ cache: false
20
20
  }
21
21
  end
22
22
 
23
+ def guess_service
24
+
25
+ locale = ENV['LANG']
26
+
27
+ #STDERR.puts("Detected locale #{locale}")
28
+
29
+ service = case locale
30
+ when 'en_GB.UTF-8'
31
+ 'http://mdq.ukfederation.org.uk/'
32
+ when 'en_US.UTF-8'
33
+ 'http://mdq-beta.incommon.org/global'
34
+ else
35
+ abort "Please specify an MDQ service using --service, MDQT_SERVICE or MDQ_BASE_URL"
36
+ end
37
+
38
+ STDERR.puts "MDQT is assuming that you want to use #{service}\nPlease configure this using --service, MDQT_SERVICE or MDQ_BASE_URL\n\n"
39
+
40
+ service
41
+
42
+ end
43
+
23
44
  end
24
45
 
25
46
  end
@@ -6,26 +6,58 @@ module MDQT
6
6
 
7
7
  class Get < Base
8
8
 
9
- def run(args, options)
9
+ def run
10
10
 
11
- client = MDQT::Client.new(base_url: options.service)
11
+ abort("Please specify --all if you wish to request all entities from #{options.service}") if args.empty? && !options.all
12
12
 
13
- if args.empty?
13
+ results = get_results(args, options)
14
14
 
15
- if options.all
16
- results = [client.get_metadata("")]
17
- else
18
- abort("Please specify --all if you wish to request all entities from #{options.service}")
19
- end
15
+ #results = MetadataValidator.validate_responses(results) if options.validate
20
16
 
17
+ #results = MetadataAggregator.aggregate_responses(results) if options.aggregate
18
+
19
+ output_metadata(results, options)
20
+
21
+ end
22
+
23
+ def get_results(args, options)
24
+
25
+ client = MDQT::Client.new(
26
+ options.service,
27
+ verbose: options.verbose,
28
+ cache_type: options.cache ? :file : :none
29
+ )
30
+
31
+ args.empty? ? [client.get_metadata("")] : args.collect {|entity_id| client.get_metadata(entity_id)}
32
+
33
+ end
34
+
35
+ def output_metadata(results, options)
36
+ case action(results, options)
37
+ when :save_files
38
+ output_files(results, options)
39
+ when :print_to_stdout
40
+ output_to_stdout(results, options)
21
41
  else
22
- results = args.collect {|entity_id| client.get_metadata(entity_id)}
42
+ abort "Error - can't determine output type"
23
43
  end
44
+ end
24
45
 
25
- results.each do |result|
26
- puts result.body
46
+ def action(results, options)
47
+ case
48
+ when options.save
49
+ :save_files
50
+ else
51
+ :print_to_stdout
27
52
  end
53
+ end
54
+
55
+ def output_to_stdout(results, options)
56
+ results.each {|r| puts output(r)}
57
+ end
28
58
 
59
+ def output_files(results, options)
60
+ abort "Unimplemented feature"
29
61
  end
30
62
 
31
63
  end
File without changes
@@ -3,27 +3,40 @@ module MDQT
3
3
 
4
4
  require 'mdqt/client/metadata_service'
5
5
 
6
- def initialize(options={})
6
+ def initialize(base_url, options={})
7
7
 
8
- @base_url = options[:base_url]
9
- @md_service = MetadataService.new(@base_url)
8
+ @base_url = base_url
9
+ @verbose = options[:verbose] || false
10
+ @cache_type = options[:cache_type] || :none
11
+
12
+ @md_service = MetadataService.new(@base_url, verbose: @verbose, cache_type: @cache_type)
10
13
 
11
14
  end
12
15
 
13
16
  def get_metadata(entity_id)
14
17
 
15
- result = md_service.get(entity_id)
18
+ md_service.get(entity_id)
16
19
 
17
20
  end
18
21
 
19
- def md_service
20
- @md_service
21
- end
22
-
23
22
  def base_url
24
23
  @base_url
25
24
  end
26
25
 
26
+ def verbose?
27
+ @verbose
28
+ end
29
+
30
+ def cache_type
31
+ @cache_type
32
+ end
33
+
34
+ private
35
+
36
+ def md_service
37
+ @md_service
38
+ end
39
+
27
40
  end
28
41
 
29
42
  end
@@ -0,0 +1,101 @@
1
+ module MDQT
2
+ class Client
3
+
4
+ class MetadataResponse
5
+
6
+ require 'digest'
7
+
8
+ def initialize(identifier, service, http_response)
9
+
10
+ @requested_identitier = identifier
11
+ @identifier = URI.decode(identifier)
12
+ @service = service
13
+ @code = http_response.status || 500
14
+ @data = http_response.body || ""
15
+ @type = http_response.headers['Content-Type']
16
+ @expires = http_response.headers['Expires']
17
+ @etag = http_response.headers['ETag']
18
+ @last_modified = http_response.headers['Last-Modified']
19
+ @ok = http_response.success?
20
+ end
21
+
22
+ def identifier
23
+ @identifier
24
+ end
25
+
26
+ def requested_identifier
27
+ @identifier
28
+ end
29
+
30
+ def service
31
+ @service
32
+ end
33
+
34
+ def code
35
+ @code
36
+ end
37
+
38
+ def data
39
+ @data || ""
40
+ end
41
+
42
+ def type
43
+ @type
44
+ end
45
+
46
+ def expires
47
+ @expires
48
+ end
49
+
50
+ def etag
51
+ @etag
52
+ end
53
+
54
+ def last_modified
55
+ @last_modified
56
+ end
57
+
58
+ def ok?
59
+ @ok
60
+ end
61
+
62
+ def signed?
63
+ @data.include? "<Signature" # This is... not great
64
+ end
65
+
66
+ def filename
67
+ "#{Digest::SHA1.hexdigest(@identifier)}.xml"
68
+ end
69
+
70
+ def message
71
+ case code
72
+ when 200
73
+ "[200] OK! Data for '#{identifier}' has been downloaded from #{service}"
74
+ when 304
75
+ "[200] OK! Data for '#{identifier}' is already available in a local cache"
76
+ when 400
77
+ "[400] The identifier '#{identifier}' ('#{requested_identifier}') is malformed or service URL #{service} is incorrect"
78
+ when 401
79
+ "[401] Credentials are incorrect or missing for '#{identifier}'"
80
+ when 403
81
+ identifier.empty? ? "[403] The MDQ service at #{service} does not support aggregate downloads" :
82
+ "[403] You do not have access rights to '#{identifier}' at #{service}"
83
+ when 404
84
+ identifier.empty? ? "[404] The MDQ service at #{service} is not responding with aggregated metadata or the correct status" :
85
+ "[404] Entity metadata for '#{identifier}' was not found at #{service}"
86
+ when 405
87
+ "[405] The service at #{service} believes the wrong HTTP method was used. We should have used HTTP GET..."
88
+ when 406
89
+ "[406] The requested content type is not available at #{service}"
90
+ when 505
91
+ "[505] The service at #{service} claims our request was using pre-1999 web protocols, not HTTP 1.1 or later"
92
+ else
93
+ "[#{code}] Sorry - an unknown error has occured requesting '#{identifier}' from #{service}.\nPlease report this bug!"
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -8,10 +8,21 @@ module MDQT
8
8
  require 'typhoeus/adapters/faraday'
9
9
  require 'cgi'
10
10
 
11
- def initialize(base_url)
11
+ require 'faraday_middleware'
12
+ require 'faraday-http-cache'
12
13
 
13
- @base_url = base_url
14
+ require 'active_support/cache'
15
+ require 'active_support/cache/file_store'
16
+ require 'active_support/cache/mem_cache_store'
17
+ require 'active_support/logger'
18
+
19
+ require_relative './metadata_response'
14
20
 
21
+ def initialize(base_url, options = {})
22
+ @base_url = base_url
23
+ @cache_type = options[:cache_type] ? options[:cache_type].to_sym : :none
24
+ @store_config = options[:cache_store]
25
+ @verbose = options[:verbose] ? true : false
15
26
  end
16
27
 
17
28
  def base_url
@@ -22,13 +33,18 @@ module MDQT
22
33
 
23
34
  entity_id = prepare_id(entity_id)
24
35
 
25
- connection.get do |req|
26
- req.url ['entities/', entity_id].join
27
- req.options.timeout = 100
28
- req.options.open_timeout = 5
29
- req.headers['Content-Type'] = 'application/samlmetadata+xml'
30
- req.headers['User-Agent'] = "MDQT v#{MDQT::VERSION}"
36
+ begin
37
+ http_response = connection.get do |req|
38
+ req.url request_path(entity_id)
39
+ req.options.timeout = 100
40
+ req.options.open_timeout = 5
41
+ end
42
+ rescue Faraday::ConnectionFailed => oops
43
+ abort "Error - can't connect to MDQ service at URL #{base_url}"
31
44
  end
45
+
46
+ MetadataResponse.new(entity_id, base_url, http_response)
47
+
32
48
  end
33
49
 
34
50
  def prepare_id(id)
@@ -38,17 +54,83 @@ module MDQT
38
54
  when /^{sha1}/i
39
55
  CGI.escape(id.downcase.strip)
40
56
  when /^\[sha1\]/i
41
- CGI.escape(id.downcase.strip.gsub"[sha1]","{sha1}")
57
+ CGI.escape(id.downcase.strip.gsub "[sha1]", "{sha1}")
42
58
  else
43
59
  CGI.escape(id.strip)
44
60
  end
45
61
  end
46
62
 
63
+ def verbose?
64
+ @verbose
65
+ end
66
+
67
+ def cache?
68
+ cache_type == :none ? false : true
69
+ end
70
+
71
+ def cache_type
72
+ @cache_type || :none
73
+ end
74
+
75
+ def store_config
76
+ @store_config || default_store_config
77
+ end
78
+
79
+ private
80
+
81
+ def request_path(entity_id)
82
+ case entity_id
83
+ when nil, ""
84
+ 'entities'
85
+ else
86
+ ['entities', entity_id].join('/')
87
+ end
88
+ end
89
+
47
90
  def connection
48
91
  Faraday.new(:url => base_url) do |faraday|
49
92
  faraday.request :url_encoded
50
- #faraday.response :logger # log requests to STDOUT
93
+ faraday.use FaradayMiddleware::Gzip
94
+ faraday.use FaradayMiddleware::FollowRedirects
95
+ faraday.use :http_cache, faraday_cache_config if cache?
96
+ faraday.headers['Content-Type'] = 'application/samlmetadata+xml'
97
+ faraday.headers['User-Agent'] = "MDQT v#{MDQT::VERSION}"
51
98
  faraday.adapter :typhoeus
99
+ #faraday.response :logger
100
+ end
101
+ end
102
+
103
+ def default_store_config
104
+ case cache_type
105
+ when :none, nil
106
+ nil
107
+ when :file, :files
108
+ File.absolute_path(File.join(Dir.tmpdir, 'mdqt_cache'))
109
+ when :memcached, :memcache
110
+ 'localhost:11211'
111
+ end
112
+ end
113
+
114
+ def faraday_cache_config
115
+ {
116
+ store: cache_store,
117
+ shared_cache: false,
118
+ serializer: Marshal,
119
+ #logger: cache_logger,
120
+ instrumenter: ActiveSupport::Notifications
121
+ }
122
+ end
123
+
124
+ def cache_logger
125
+ verbose? ? Logger.new('mdqt_cache.log') : nil
126
+ end
127
+
128
+ def cache_store
129
+ case cache_type
130
+ when :file, :files, nil
131
+ @cache_store = ActiveSupport::Cache.lookup_store(:file_store, store_config)
132
+ when :memcache, :memcached
133
+ @cache_store = ActiveSupport::Cache.lookup_store(:mem_cache_store, [store_config])
52
134
  end
53
135
  end
54
136
 
@@ -0,0 +1,23 @@
1
+ module MDQT
2
+ class Client
3
+
4
+ class MetadataValidator
5
+
6
+ def initialize(response)
7
+
8
+ puts response.inspect
9
+
10
+ end
11
+
12
+
13
+ def ok?
14
+ true
15
+ end
16
+
17
+
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -1,3 +1,3 @@
1
1
  module MDQT
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'cucumber'
3
+ require 'cucumber/rake/task'
4
+
5
+ desc "Run Cucumber tests"
6
+ Cucumber::Rake::Task.new(:features) do |t|
7
+ t.cucumber_opts = "features --format pretty"
8
+ end
@@ -0,0 +1,5 @@
1
+ require "rspec/core/rake_task"
2
+
3
+
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,6 @@
1
+
2
+ desc "Run all tests and gather coverage information"
3
+ task :tests => [:spec, :features] do
4
+
5
+
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['features/*.feature', 'features/*.rb']
5
+ t.options = ['--any', '--extra', '--opts'] # optional
6
+ end
@@ -9,11 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Pete Birkinshaw"]
10
10
  spec.email = ["pete@digitalidentitylabs.com"]
11
11
 
12
- spec.summary = %q{Library and utility for accessing MDQ services}
13
- spec.description = %q{Library and utility for accessing MDQ service}
12
+ spec.summary = %q{Library and commandline utility for accessing MDQ services}
13
+ spec.description = %q{Library and commandline utility for downloading SAML metadata from MDQ services}
14
14
  spec.homepage = "https://github.com/Digital-Identity-Labs/mdqt"
15
15
  spec.license = "MIT"
16
16
 
17
+ spec.required_ruby_version = '>= 2.1.0'
18
+
17
19
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
20
  # to allow pushing to a single host or delete this section to allow pushing to any host.
19
21
  # if spec.respond_to?(:metadata)
@@ -30,13 +32,22 @@ Gem::Specification.new do |spec|
30
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
33
  spec.require_paths = ["lib"]
32
34
 
33
- spec.add_dependency "faraday", "~>0.15"
35
+ spec.add_dependency 'commander', "~>4.4"
36
+ spec.add_dependency 'faraday', "~>0.15"
37
+ spec.add_dependency 'faraday_middleware', "~>0.12"
34
38
  spec.add_dependency 'faraday-http-cache', "~>2.0"
35
- spec.add_dependency "typhoeus", "~>1.3"
36
- spec.add_dependency "commander", "~>4.4"
39
+ spec.add_dependency 'typhoeus', "~>1.3"
40
+ spec.add_dependency 'activesupport', "~>5.2"
41
+ spec.add_dependency 'dalli', "~>2.7"
37
42
 
43
+ #spec.add_dependency 'xmldsig'
38
44
 
39
45
  spec.add_development_dependency "bundler", "~> 1.13"
40
46
  spec.add_development_dependency "rake", "~> 10.0"
41
47
  spec.add_development_dependency "rspec", "~> 3.0"
48
+ spec.add_development_dependency "cucumber", "~> 3.1"
49
+ spec.add_development_dependency "aruba", "~> 0.14"
50
+ spec.add_development_dependency "vcr", "~> 4.0"
51
+ spec.add_development_dependency "yard", "~> 0.9"
52
+ spec.add_development_dependency "yard-cucumber", "~> 4.0"
42
53
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mdqt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Birkinshaw
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-02 00:00:00.000000000 Z
11
+ date: 2018-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: commander
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.4'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday_middleware
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.12'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.12'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: faraday-http-cache
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -53,19 +81,33 @@ dependencies:
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.3'
55
83
  - !ruby/object:Gem::Dependency
56
- name: commander
84
+ name: activesupport
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '4.4'
89
+ version: '5.2'
62
90
  type: :runtime
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '4.4'
96
+ version: '5.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dalli
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.7'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.7'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: bundler
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +150,78 @@ dependencies:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
152
  version: '3.0'
111
- description: Library and utility for accessing MDQ service
153
+ - !ruby/object:Gem::Dependency
154
+ name: cucumber
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: aruba
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.14'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.14'
181
+ - !ruby/object:Gem::Dependency
182
+ name: vcr
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '4.0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '4.0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: yard
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '0.9'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '0.9'
209
+ - !ruby/object:Gem::Dependency
210
+ name: yard-cucumber
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '4.0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '4.0'
223
+ description: Library and commandline utility for downloading SAML metadata from MDQ
224
+ services
112
225
  email:
113
226
  - pete@digitalidentitylabs.com
114
227
  executables:
@@ -118,8 +231,11 @@ extra_rdoc_files: []
118
231
  files:
119
232
  - ".gitignore"
120
233
  - ".rspec"
234
+ - ".rubocop.yml"
235
+ - ".rubocop_todo.yml"
121
236
  - ".ruby-version"
122
237
  - ".travis.yml"
238
+ - CHANGELOG.md
123
239
  - CODE_OF_CONDUCT.md
124
240
  - Gemfile
125
241
  - LICENSE.txt
@@ -131,11 +247,20 @@ files:
131
247
  - lib/mdqt.rb
132
248
  - lib/mdqt/cli.rb
133
249
  - lib/mdqt/cli/base.rb
250
+ - lib/mdqt/cli/clean.rb
251
+ - lib/mdqt/cli/compliance.rb
134
252
  - lib/mdqt/cli/defaults.rb
135
253
  - lib/mdqt/cli/get.rb
254
+ - lib/mdqt/cli/stream.rb
136
255
  - lib/mdqt/client.rb
256
+ - lib/mdqt/client/metadata_response.rb
137
257
  - lib/mdqt/client/metadata_service.rb
258
+ - lib/mdqt/client/metadata_validator.rb
138
259
  - lib/mdqt/version.rb
260
+ - lib/tasks/cucumber.rake
261
+ - lib/tasks/spec.rake
262
+ - lib/tasks/tests.rake
263
+ - lib/tasks/yard.rake
139
264
  - mdqt.gemspec
140
265
  homepage: https://github.com/Digital-Identity-Labs/mdqt
141
266
  licenses:
@@ -149,7 +274,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
274
  requirements:
150
275
  - - ">="
151
276
  - !ruby/object:Gem::Version
152
- version: '0'
277
+ version: 2.1.0
153
278
  required_rubygems_version: !ruby/object:Gem::Requirement
154
279
  requirements:
155
280
  - - ">="
@@ -160,5 +285,5 @@ rubyforge_project:
160
285
  rubygems_version: 2.7.3
161
286
  signing_key:
162
287
  specification_version: 4
163
- summary: Library and utility for accessing MDQ services
288
+ summary: Library and commandline utility for accessing MDQ services
164
289
  test_files: []