Skip to content

Commit

Permalink
Merge pull request #622 from nholden/strict-audience-validation
Browse files Browse the repository at this point in the history
Add security setting to more strictly enforce audience validation
  • Loading branch information
pitbulk committed Oct 14, 2021
2 parents 292aacc + 732e6e2 commit 74c2545
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,29 @@ validation fails. You may disable such exceptions using the `settings.security[:
settings.security[:soft] = true # Do not raise error on failed signature/certificate validations
```
#### Audience Validation
A service provider should only consider a SAML response valid if the IdP includes an <AudienceRestriction>
element containting an <Audience> element that uniquely identifies the service provider. Unless you specify
the `skip_audience` option, Ruby SAML will validate that each SAML response includes an <Audience> element
whose contents matches `settings.sp_entity_id`.
By default, Ruby SAML considers an <AudienceRestriction> element containing only empty <Audience> elements
to be valid. That means an otherwise valid SAML response with a condition like this would be valid:
```xml
<AudienceRestriction>
<Audience />
</AudienceRestriction>
```
You may enforce that an <AudienceRestriction> element containing only empty <Audience> elements
is invalid using the `settings.security[:strict_audience_validation]` parameter.
```ruby
settings.security[:strict_audience_validation] = true
```
#### Key Rollover
To update the SP X.509 certificate and private key without disruption of service, you may define the parameter
Expand Down
7 changes: 6 additions & 1 deletion lib/onelogin/ruby-saml/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,12 @@ def validate_in_response_to
#
def validate_audience
return true if options[:skip_audience]
return true if audiences.empty? || settings.sp_entity_id.nil? || settings.sp_entity_id.empty?
return true if settings.sp_entity_id.nil? || settings.sp_entity_id.empty?

if audiences.empty?
return true unless settings.security[:strict_audience_validation]
return append_error("Invalid Audiences. The <AudienceRestriction> element contained only empty <Audience> elements. Expected audience #{settings.sp_entity_id}.")
end

unless audiences.include? settings.sp_entity_id
s = audiences.count > 1 ? 's' : '';
Expand Down
3 changes: 2 additions & 1 deletion lib/onelogin/ruby-saml/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ def get_binding(value)
:digest_method => XMLSecurity::Document::SHA1,
:signature_method => XMLSecurity::Document::RSA_SHA1,
:check_idp_cert_expiration => false,
:check_sp_cert_expiration => false
:check_sp_cert_expiration => false,
:strict_audience_validation => false,
}.freeze
}.freeze
end
Expand Down
12 changes: 10 additions & 2 deletions test/response_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -490,14 +490,22 @@ def generate_audience_error(expected, actual)
assert_empty response.errors
end

it "return true when the audience is self closing" do
it "return true when the audience is self closing and strict audience validation is not enabled" do
response_audience_self_closed.settings = settings
response_audience_self_closed.settings.sp_entity_id = '{audience}'
assert response_audience_self_closed.send(:validate_audience)
assert_empty response_audience_self_closed.errors
end

it "return false when the audience is valid" do
it "return false when the audience is self closing and strict audience validation is enabled" do
response_audience_self_closed.settings = settings
response_audience_self_closed.settings.security[:strict_audience_validation] = true
response_audience_self_closed.settings.sp_entity_id = '{audience}'
refute response_audience_self_closed.send(:validate_audience)
assert_includes response_audience_self_closed.errors, "Invalid Audiences. The <AudienceRestriction> element contained only empty <Audience> elements. Expected audience {audience}."
end

it "return false when the audience is invalid" do
response.settings = settings
response.settings.sp_entity_id = 'invalid_audience'
assert !response.send(:validate_audience)
Expand Down

0 comments on commit 74c2545

Please sign in to comment.