saml_idp 0.7.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +1 -1
  3. data/README.md +40 -12
  4. data/lib/saml_idp/configurator.rb +1 -0
  5. data/lib/saml_idp/controller.rb +6 -2
  6. data/lib/saml_idp/encryptor.rb +1 -1
  7. data/lib/saml_idp/incoming_metadata.rb +9 -1
  8. data/lib/saml_idp/request.rb +14 -0
  9. data/lib/saml_idp/response_builder.rb +19 -5
  10. data/lib/saml_idp/saml_response.rb +15 -3
  11. data/lib/saml_idp/service_provider.rb +14 -0
  12. data/lib/saml_idp/signable.rb +1 -2
  13. data/lib/saml_idp/version.rb +1 -1
  14. data/lib/saml_idp/xml_security.rb +1 -1
  15. data/saml_idp.gemspec +26 -23
  16. data/spec/acceptance/idp_controller_spec.rb +5 -4
  17. data/spec/lib/saml_idp/algorithmable_spec.rb +6 -6
  18. data/spec/lib/saml_idp/assertion_builder_spec.rb +8 -8
  19. data/spec/lib/saml_idp/attribute_decorator_spec.rb +8 -8
  20. data/spec/lib/saml_idp/configurator_spec.rb +7 -7
  21. data/spec/lib/saml_idp/controller_spec.rb +23 -20
  22. data/spec/lib/saml_idp/encryptor_spec.rb +4 -4
  23. data/spec/lib/saml_idp/incoming_metadata_spec.rb +46 -0
  24. data/spec/lib/saml_idp/metadata_builder_spec.rb +7 -17
  25. data/spec/lib/saml_idp/name_id_formatter_spec.rb +3 -3
  26. data/spec/lib/saml_idp/request_spec.rb +22 -22
  27. data/spec/lib/saml_idp/response_builder_spec.rb +5 -3
  28. data/spec/lib/saml_idp/saml_response_spec.rb +31 -8
  29. data/spec/lib/saml_idp/service_provider_spec.rb +2 -2
  30. data/spec/lib/saml_idp/signable_spec.rb +1 -1
  31. data/spec/lib/saml_idp/signature_builder_spec.rb +2 -2
  32. data/spec/lib/saml_idp/signed_info_builder_spec.rb +3 -3
  33. data/spec/rails_app/app/controllers/saml_controller.rb +5 -1
  34. data/spec/rails_app/config/application.rb +0 -6
  35. data/spec/rails_app/config/environments/development.rb +1 -6
  36. data/spec/rails_app/config/environments/production.rb +1 -0
  37. data/spec/rails_app/config/environments/test.rb +1 -0
  38. data/spec/spec_helper.rb +3 -0
  39. data/spec/support/saml_request_macros.rb +2 -1
  40. data/spec/xml_security_spec.rb +12 -12
  41. metadata +85 -40
  42. data/spec/lib/saml_idp/.assertion_builder_spec.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f5e1bd3ed3c6f24d3a0793606d08e6eb99d51eb8
4
- data.tar.gz: 29215034a6b59ee05a73da302a986f516e8e7ad8
2
+ SHA256:
3
+ metadata.gz: 1a69c8d8c945c47e87cb526d4dfcf5f30c2f687d03b33e99013eef63acbe4377
4
+ data.tar.gz: 4933af3eb5cb686111307cd86d074ab45cc879a253f7a0833aaaa3262add74db
5
5
  SHA512:
6
- metadata.gz: f2231a17b50851ee8d7c370b1b2ff4c372430ce5bae98e7c4e840a93b0985a29c4ed242c634b80ccd94fa9c47391b0a8987fb5267a718192ace7346eb18db098
7
- data.tar.gz: 71e4162bd719e566bbb85f37c7ed84c50ec241211275c405f24da83eddbffbda4fdd21918d8e8042139968cec1d4b2171358ef31ec44895827e486485e715199
6
+ metadata.gz: 61d5e37801af0e41b71cdf0bdbac6cac61e0b86969de75c27519b74ede55e3b9c2ec7c2dfc8bff9ef82ec1fa1a870c9483fe31e65e17d645fdf6cab5205ac2d1
7
+ data.tar.gz: a1594a0f1da0694a93c478259dcece4d38c30863564aa653b585bdae9ef6834699b784ff151b7569e7cccee22b41e0b5a37f0a5151a89b664feda92005f3f21f
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
  gemspec
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Ruby SAML Identity Provider (IdP)
2
+
2
3
  Forked from https://github.com/lawrencepit/ruby-saml-idp
3
4
 
4
- [![Build Status](https://travis-ci.org/sportngin/saml_idp.png)](https://travis-ci.org/sportngin/saml_idp)
5
- [![Gem Version](https://badge.fury.io/rb/saml_idp.png)](http://badge.fury.io/rb/saml_idp)
5
+ [![Build Status](https://travis-ci.org/saml-idp/saml_idp.svg)](https://travis-ci.org/saml-idp/saml_idp)
6
+ [![Gem Version](https://badge.fury.io/rb/saml_idp.svg)](http://badge.fury.io/rb/saml_idp)
6
7
 
7
8
  The ruby SAML Identity Provider library is for implementing the server side of SAML authentication. It allows
8
9
  your application to act as an IdP (Identity Provider) using the
@@ -19,6 +20,7 @@ Add this to your Gemfile:
19
20
  gem 'saml_idp'
20
21
 
21
22
  ## Not using rails?
23
+
22
24
  Include `SamlIdp::Controller` and see the examples that use rails. It should be straightforward for you.
23
25
 
24
26
  Basically you call `decode_request(params[:SAMLRequest])` on an incoming request and then use the value
@@ -30,9 +32,10 @@ posting to `saml_acs_url` the parameter `SAMLResponse` with the return value fro
30
32
  `encode_response(user_email)`.
31
33
 
32
34
  ## Using rails?
35
+
33
36
  Add to your `routes.rb` file, for example:
34
37
 
35
- ``` ruby
38
+ ```ruby
36
39
  get '/saml/auth' => 'saml_idp#new'
37
40
  get '/saml/metadata' => 'saml_idp#show'
38
41
  post '/saml/auth' => 'saml_idp#create'
@@ -41,7 +44,7 @@ match '/saml/logout' => 'saml_idp#logout', via: [:get, :post, :delete]
41
44
 
42
45
  Create a controller that looks like this, customize to your own situation:
43
46
 
44
- ``` ruby
47
+ ```ruby
45
48
  class SamlIdpController < SamlIdp::IdpController
46
49
  def idp_authenticate(email, password) # not using params intentionally
47
50
  user = User.by_email(email).first
@@ -69,6 +72,22 @@ end
69
72
 
70
73
  ## Configuration
71
74
 
75
+ #### Signed assertions and Signed Response
76
+
77
+ By default SAML Assertion will be signed with an algorithm which defined to `config.algorithm`. Because SAML assertions contain secure information used for authentication such as NameID.
78
+
79
+ Signing SAML Response is optional, but some security perspective SP services might require Response message itself must be signed.
80
+ For that, you can enable it with `config.signed_message` option. [More about SAML spec](https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=68)
81
+
82
+ #### Signing algorithm
83
+
84
+ Following algorithms you can set in your response signing algorithm
85
+ :sha1 - RSA-SHA1 default value but not recommended to production environment
86
+ Highly recommended to use one of following algorithm, suit with your computing power.
87
+ :sha256 - RSA-SHA256
88
+ :sha384 - RSA-SHA384
89
+ :sha512 - RSA-SHA512
90
+
72
91
  Be sure to load a file like this during your app initialization:
73
92
 
74
93
  ```ruby
@@ -88,18 +107,21 @@ KEY DATA
88
107
  CERT
89
108
 
90
109
  # config.password = "secret_key_password"
91
- # config.algorithm = :sha256
110
+ # config.algorithm = :sha256 # Default: sha1 only for development.
92
111
  # config.organization_name = "Your Organization"
93
112
  # config.organization_url = "http://example.com"
94
113
  # config.base_saml_location = "#{base}/saml"
95
114
  # config.reference_id_generator # Default: -> { UUID.generate }
115
+ # config.single_logout_service_post_location = "#{base}/saml/logout"
116
+ # config.single_logout_service_redirect_location = "#{base}/saml/logout"
96
117
  # config.attribute_service_location = "#{base}/saml/attributes"
97
118
  # config.single_service_post_location = "#{base}/saml/auth"
98
119
  # config.session_expiry = 86400 # Default: 0 which means never
120
+ # config.signed_message = true # Default: false which means unsigned SAML Response
99
121
 
100
122
  # Principal (e.g. User) is passed in when you `encode_response`
101
123
  #
102
- # config.name_id.formats # =>
124
+ # config.name_id.formats =
103
125
  # { # All 2.0
104
126
  # email_address: -> (principal) { principal.email_address },
105
127
  # transient: -> (principal) { principal.id },
@@ -169,7 +191,11 @@ CERT
169
191
  service_providers = {
170
192
  "some-issuer-url.com/saml" => {
171
193
  fingerprint: "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D",
172
- metadata_url: "http://some-issuer-url.com/saml/metadata"
194
+ metadata_url: "http://some-issuer-url.com/saml/metadata",
195
+
196
+ # We now validate AssertionConsumerServiceURL will match the MetadataURL set above.
197
+ # *If* it's not going to match your Metadata URL's Host, then set this so we can validate the host using this list
198
+ response_hosts: ["foo.some-issuer-url.com"]
173
199
  },
174
200
  }
175
201
 
@@ -177,7 +203,7 @@ CERT
177
203
  # settings is an IncomingMetadata object which has a to_h method that needs to be persisted
178
204
  config.service_provider.metadata_persister = ->(identifier, settings) {
179
205
  fname = identifier.to_s.gsub(/\/|:/,"_")
180
- `mkdir -p #{Rails.root.join("cache/saml/metadata")}`
206
+ FileUtils.mkdir_p(Rails.root.join('cache', 'saml', 'metadata').to_s)
181
207
  File.open Rails.root.join("cache/saml/metadata/#{fname}"), "r+b" do |f|
182
208
  Marshal.dump settings.to_h, f
183
209
  end
@@ -188,7 +214,7 @@ CERT
188
214
  # `service_provider` you should return the settings.to_h from above
189
215
  config.service_provider.persisted_metadata_getter = ->(identifier, service_provider){
190
216
  fname = identifier.to_s.gsub(/\/|:/,"_")
191
- `mkdir -p #{Rails.root.join("cache/saml/metadata")}`
217
+ FileUtils.mkdir_p(Rails.root.join('cache', 'saml', 'metadata').to_s)
192
218
  full_filename = Rails.root.join("cache/saml/metadata/#{fname}")
193
219
  if File.file?(full_filename)
194
220
  File.open full_filename, "rb" do |f|
@@ -205,6 +231,7 @@ end
205
231
  ```
206
232
 
207
233
  # Keys and Secrets
234
+
208
235
  To generate the SAML Response it uses a default X.509 certificate and secret key... which isn't so secret.
209
236
  You can find them in `SamlIdp::Default`. The X.509 certificate is valid until year 2032.
210
237
  Obviously you shouldn't use these if you intend to use this in production environments. In that case,
@@ -218,18 +245,19 @@ The fingerprint to use, if you use the default X.509 certificate of this gem, is
218
245
  9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D
219
246
  ```
220
247
 
221
-
222
248
  # Service Providers
249
+
223
250
  To act as a Service Provider which generates SAML Requests and can react to SAML Responses use the
224
251
  excellent [ruby-saml](https://github.com/onelogin/ruby-saml) gem.
225
252
 
226
-
227
253
  # Author
228
- Jon Phenow, me@jphenow.com
254
+
255
+ Jon Phenow, jon@jphenow.com, jphenow.com, @jphenow
229
256
 
230
257
  Lawrence Pit, lawrence.pit@gmail.com, lawrencepit.com, @lawrencepit
231
258
 
232
259
  # Copyright
260
+
233
261
  Copyright (c) 2012 Sport Ngin.
234
262
  Portions Copyright (c) 2010 OneLogin, LLC
235
263
  Portions Copyright (c) 2012 Lawrence Pit (http://lawrencepit.com)
@@ -17,6 +17,7 @@ module SamlIdp
17
17
  attr_accessor :single_logout_service_redirect_location
18
18
  attr_accessor :attributes
19
19
  attr_accessor :service_provider
20
+ attr_accessor :assertion_consumer_service_hosts
20
21
  attr_accessor :session_expiry
21
22
 
22
23
  def initialize
@@ -35,13 +35,15 @@ module SamlIdp
35
35
 
36
36
  def validate_saml_request(raw_saml_request = params[:SAMLRequest])
37
37
  decode_request(raw_saml_request)
38
- unless valid_saml_request?
38
+ return true if valid_saml_request?
39
+ if defined?(::Rails)
39
40
  if Rails::VERSION::MAJOR >= 4
40
41
  head :forbidden
41
42
  else
42
43
  render nothing: true, status: :forbidden
43
44
  end
44
45
  end
46
+ false
45
47
  end
46
48
 
47
49
  def decode_request(raw_saml_request)
@@ -62,6 +64,7 @@ module SamlIdp
62
64
  expiry = opts[:expiry] || 60*60
63
65
  session_expiry = opts[:session_expiry]
64
66
  encryption_opts = opts[:encryption] || nil
67
+ signed_message_opts = opts[:signed_message] || false
65
68
 
66
69
  SamlResponse.new(
67
70
  reference_id,
@@ -75,7 +78,8 @@ module SamlIdp
75
78
  my_authn_context_classref,
76
79
  expiry,
77
80
  encryption_opts,
78
- session_expiry
81
+ session_expiry,
82
+ signed_message_opts
79
83
  ).build
80
84
  end
81
85
 
@@ -72,7 +72,7 @@ module SamlIdp
72
72
  cipher_data.CipherValue
73
73
  end
74
74
  enc_key.ReferenceList do |ref_list|
75
- ref_list.DataReference URI: 'ED'
75
+ ref_list.DataReference URI: '#ED'
76
76
  end
77
77
  end
78
78
  end
@@ -16,13 +16,21 @@ module SamlIdp
16
16
  @document ||= Saml::XML::Document.parse raw
17
17
  end
18
18
 
19
+ def entity_id
20
+ xpath('//md:EntityDescriptor/@entityID', md: metadata_namespace).first.try(:content).to_s
21
+ end
22
+ hashable :entity_id
23
+
19
24
  def sign_assertions
20
25
  doc = xpath(
21
26
  "//md:SPSSODescriptor",
22
27
  ds: signature_namespace,
23
28
  md: metadata_namespace
24
29
  ).first
25
- doc ? !!doc["WantAssertionsSigned"] : false
30
+ if (doc && !doc['WantAssertionsSigned'].nil?)
31
+ return doc['WantAssertionsSigned'].strip.downcase == 'true'
32
+ end
33
+ return false
26
34
  end
27
35
  hashable :sign_assertions
28
36
 
@@ -105,6 +105,12 @@ module SamlIdp
105
105
  return false
106
106
  end
107
107
 
108
+ if !service_provider.acceptable_response_hosts.include?(response_host)
109
+ log "#{service_provider.acceptable_response_hosts} compare to #{response_host}"
110
+ log "No acceptable AssertionConsumerServiceURL, either configure them via config.service_provider.response_hosts or match to your metadata_url host"
111
+ return false
112
+ end
113
+
108
114
  return true
109
115
  end
110
116
 
@@ -136,6 +142,14 @@ module SamlIdp
136
142
  @_session_index ||= xpath("//samlp:SessionIndex", samlp: samlp).first.try(:content)
137
143
  end
138
144
 
145
+ def response_host
146
+ uri = URI(response_url)
147
+ if uri
148
+ uri.host
149
+ end
150
+ end
151
+ private :response_host
152
+
139
153
  def document
140
154
  @_document ||= Saml::XML::Document.parse(raw_xml)
141
155
  end
@@ -1,32 +1,45 @@
1
1
  require 'builder'
2
+ require 'saml_idp/algorithmable'
3
+ require 'saml_idp/signable'
2
4
  module SamlIdp
3
5
  class ResponseBuilder
6
+ include Algorithmable
7
+ include Signable
4
8
  attr_accessor :response_id
5
9
  attr_accessor :issuer_uri
6
10
  attr_accessor :saml_acs_url
7
11
  attr_accessor :saml_request_id
8
12
  attr_accessor :assertion_and_signature
13
+ attr_accessor :raw_algorithm
9
14
 
10
- def initialize(response_id, issuer_uri, saml_acs_url, saml_request_id, assertion_and_signature)
15
+ alias_method :reference_id, :response_id
16
+
17
+ def initialize(response_id, issuer_uri, saml_acs_url, saml_request_id, assertion_and_signature, raw_algorithm)
11
18
  self.response_id = response_id
12
19
  self.issuer_uri = issuer_uri
13
20
  self.saml_acs_url = saml_acs_url
14
21
  self.saml_request_id = saml_request_id
15
22
  self.assertion_and_signature = assertion_and_signature
23
+ self.raw_algorithm = raw_algorithm
16
24
  end
17
25
 
18
- def encoded
19
- @encoded ||= encode
26
+ def encoded(signed_message: false)
27
+ @encoded ||= signed_message ? encode_signed_message : encode_raw_message
20
28
  end
21
29
 
22
30
  def raw
23
31
  build
24
32
  end
25
33
 
26
- def encode
34
+ def encode_raw_message
27
35
  Base64.strict_encode64(raw)
28
36
  end
29
- private :encode
37
+ private :encode_raw_message
38
+
39
+ def encode_signed_message
40
+ Base64.strict_encode64(signed)
41
+ end
42
+ private :encode_signed_message
30
43
 
31
44
  def build
32
45
  resp_options = {}
@@ -41,6 +54,7 @@ module SamlIdp
41
54
  builder = Builder::XmlMarkup.new
42
55
  builder.tag! "samlp:Response", resp_options do |response|
43
56
  response.Issuer issuer_uri, xmlns: Saml::XML::Namespaces::ASSERTION
57
+ sign response
44
58
  response.tag! "samlp:Status" do |status|
45
59
  status.tag! "samlp:StatusCode", Value: Saml::XML::Namespaces::Statuses::SUCCESS
46
60
  end
@@ -17,6 +17,7 @@ module SamlIdp
17
17
  attr_accessor :expiry
18
18
  attr_accessor :encryption_opts
19
19
  attr_accessor :session_expiry
20
+ attr_accessor :signed_message_opts
20
21
 
21
22
  def initialize(reference_id,
22
23
  response_id,
@@ -29,7 +30,8 @@ module SamlIdp
29
30
  authn_context_classref,
30
31
  expiry=60*60,
31
32
  encryption_opts=nil,
32
- session_expiry=0
33
+ session_expiry=0,
34
+ signed_message_opts
33
35
  )
34
36
  self.reference_id = reference_id
35
37
  self.response_id = response_id
@@ -45,10 +47,11 @@ module SamlIdp
45
47
  self.expiry = expiry
46
48
  self.encryption_opts = encryption_opts
47
49
  self.session_expiry = session_expiry
50
+ self.signed_message_opts = signed_message_opts
48
51
  end
49
52
 
50
53
  def build
51
- @built ||= response_builder.encoded
54
+ @built ||= encoded_message
52
55
  end
53
56
 
54
57
  def signed_assertion
@@ -60,8 +63,17 @@ module SamlIdp
60
63
  end
61
64
  private :signed_assertion
62
65
 
66
+ def encoded_message
67
+ if signed_message_opts
68
+ response_builder.encoded(signed_message: true)
69
+ else
70
+ response_builder.encoded(signed_message: false)
71
+ end
72
+ end
73
+ private :encoded_message
74
+
63
75
  def response_builder
64
- ResponseBuilder.new(response_id, issuer_uri, saml_acs_url, saml_request_id, signed_assertion)
76
+ ResponseBuilder.new(response_id, issuer_uri, saml_acs_url, saml_request_id, signed_assertion, algorithm)
65
77
  end
66
78
  private :response_builder
67
79
 
@@ -13,6 +13,7 @@ module SamlIdp
13
13
  attribute :validate_signature
14
14
  attribute :acs_url
15
15
  attribute :assertion_consumer_logout_service_url
16
+ attribute :response_hosts
16
17
 
17
18
  delegate :config, to: :SamlIdp
18
19
 
@@ -46,6 +47,19 @@ module SamlIdp
46
47
  @current_metadata ||= get_current_or_build
47
48
  end
48
49
 
50
+ def acceptable_response_hosts
51
+ hosts = Array(self.response_hosts)
52
+ hosts.push(metadata_url_host) if metadata_url_host
53
+
54
+ hosts
55
+ end
56
+
57
+ def metadata_url_host
58
+ if metadata_url.present?
59
+ URI(metadata_url).host
60
+ end
61
+ end
62
+
49
63
  def get_current_or_build
50
64
  persisted = metadata_getter[identifier, self]
51
65
  if persisted.is_a? Hash
@@ -108,8 +108,7 @@ module SamlIdp
108
108
  canon_algorithm = Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
109
109
  canon_hashed_element = noko_raw.canonicalize(canon_algorithm, inclusive_namespaces)
110
110
  digest_algorithm = get_algorithm
111
-
112
- hash = digest_algorithm.digest(canon_hashed_element)
111
+ hash = digest_algorithm.digest(canon_hashed_element)
113
112
  Base64.strict_encode64(hash).gsub(/\n/, '')
114
113
  end
115
114
  private :digest
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module SamlIdp
3
- VERSION = '0.7.1'
3
+ VERSION = '0.10.0'
4
4
  end
@@ -108,7 +108,7 @@ module SamlIdp
108
108
  canon_algorithm = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod', 'ds' => DSIG)
109
109
  canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces)
110
110
 
111
- digest_algorithm = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod"))
111
+ digest_algorithm = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod", {'ds' => DSIG}))
112
112
 
113
113
  hash = digest_algorithm.digest(canon_hashed_element)
114
114
  digest_value = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
@@ -7,28 +7,29 @@ Gem::Specification.new do |s|
7
7
  s.version = SamlIdp::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Jon Phenow"]
10
- s.email = %q{jon.phenow@sportngin.com}
11
- s.homepage = %q{http://github.com/sportngin/saml_idp}
12
- s.summary = %q{SAML Indentity Provider in ruby}
13
- s.description = %q{SAML IdP (Identity Provider) library in ruby}
10
+ s.email = 'jon.phenow@sportngin.com'
11
+ s.homepage = 'https://github.com/saml-idp/saml_idp'
12
+ s.summary = 'SAML Indentity Provider for Ruby'
13
+ s.description = 'SAML IdP (Identity Provider) Library for Ruby'
14
14
  s.date = Time.now.utc.strftime("%Y-%m-%d")
15
- s.files = Dir.glob("app/**/*") + Dir.glob("lib/**/*") + [
16
- "LICENSE",
17
- "README.md",
18
- "Gemfile",
19
- "saml_idp.gemspec"
20
- ]
15
+ s.files = Dir['app/**/*', 'lib/**/*', 'LICENSE', 'README.md', 'Gemfile', 'saml_idp.gemspec']
21
16
  s.required_ruby_version = '>= 2.2'
22
- s.license = "LICENSE"
17
+ s.license = 'MIT'
23
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
20
  s.require_paths = ["lib"]
26
- s.rdoc_options = ["--charset=UTF-8"]
21
+ s.rdoc_options = ['--charset=UTF-8']
22
+ s.metadata = {
23
+ 'homepage_uri' => 'https://github.com/saml-idp/saml_idp',
24
+ 'source_code_uri' => 'https://github.com/saml-idp/saml_idp',
25
+ 'bug_tracker_uri' => 'https://github.com/saml-idp/saml_idp/issues',
26
+ 'documentation_uri' => "http://rdoc.info/gems/saml_idp/#{SamlIdp::VERSION}"
27
+ }
27
28
 
28
29
  s.post_install_message = <<-INST
29
30
  If you're just recently updating saml_idp - please be aware we've changed the default
30
31
  certificate. See the PR and a description of why we've done this here:
31
- https://github.com/sportngin/saml_idp/pull/29
32
+ https://github.com/saml-idp/saml_idp/pull/29
32
33
 
33
34
  If you just need to see the certificate `bundle open saml_idp` and go to
34
35
  `lib/saml_idp/default.rb`
@@ -43,17 +44,19 @@ section of the README.
43
44
  INST
44
45
 
45
46
  s.add_dependency('activesupport', '>= 3.2')
46
- s.add_dependency('uuid', '~> 2.3')
47
- s.add_dependency('builder', '~> 3.0')
47
+ s.add_dependency('uuid', '>= 2.3')
48
+ s.add_dependency('builder', '>= 3.0')
48
49
  s.add_dependency('nokogiri', '>= 1.6.2')
49
50
 
50
- s.add_development_dependency('rake', '~> 10.4.2')
51
- s.add_development_dependency('simplecov', '~> 0.12')
52
- s.add_development_dependency('rspec', '~> 2.5')
53
- s.add_development_dependency('ruby-saml', '~> 1.3')
54
- s.add_development_dependency('rails', '~> 3.2')
55
- s.add_development_dependency('capybara', '~> 2.11.0')
56
- s.add_development_dependency('timecop', '~> 0.8')
51
+ s.add_development_dependency('rake')
52
+ s.add_development_dependency('simplecov')
53
+ s.add_development_dependency('rspec', '>= 3.7.0')
54
+ s.add_development_dependency('ruby-saml', '>= 1.7.2')
55
+ s.add_development_dependency('rails', '>= 3.2')
56
+ s.add_development_dependency('activeresource', '>= 3.2')
57
+ s.add_development_dependency('capybara', '>= 2.16')
58
+ s.add_development_dependency('timecop', '>= 0.8')
57
59
  s.add_development_dependency('xmlenc', '>= 0.6.4')
60
+ s.add_development_dependency('appraisal')
61
+ s.add_development_dependency('byebug')
58
62
  end
59
-