diff --git a/README.md b/README.md index df64434..41bf1ff 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Other configuration options: * `uid_field` - The user data attribute to use as your user's unique identifier. Defaults to `'user'` (which usually contains the user's login name). * `ca_path` - Optional when `ssl` is `true`. Sets path of a CA certification directory. See [Net::HTTP][net_http] for more details. * `disable_ssl_verification` - Optional when `ssl` is true. Disables verification. + * `merge_multivalued_attributes` - When set to `true` returns attributes with multiple values as arrays. Defaults to `false` and returns the last value as a string. * `on_single_sign_out` - Optional. Callback used when a [CAS 3.1 Single Sign Out][sso] request is received. * `fetch_raw_info` - Optional. Callback used to return additional "raw" user diff --git a/lib/omniauth/strategies/cas.rb b/lib/omniauth/strategies/cas.rb index 39cd951..3b00a0b 100644 --- a/lib/omniauth/strategies/cas.rb +++ b/lib/omniauth/strategies/cas.rb @@ -22,6 +22,7 @@ class InvalidCASTicket < StandardError; end option :port, nil option :path, nil option :ssl, true + option :merge_multivalued_attributes, false option :service_validate_url, '/serviceValidate' option :login_url, '/login' option :logout_url, '/logout' diff --git a/lib/omniauth/strategies/cas/service_ticket_validator.rb b/lib/omniauth/strategies/cas/service_ticket_validator.rb index b6b7936..c5d8d74 100644 --- a/lib/omniauth/strategies/cas/service_ticket_validator.rb +++ b/lib/omniauth/strategies/cas/service_ticket_validator.rb @@ -42,6 +42,16 @@ def user_info private + # Merges attributes with multiple values into an array if support is + # enabled (disabled by default) + def attribute_value(user_info, attribute, value) + if @options.merge_multivalued_attributes && user_info.key?(attribute) + Array(user_info[attribute]).push(value) + else + value + end + end + # turns an `` node into a Hash; # returns nil if given nil def parse_user_info(node) @@ -52,7 +62,7 @@ def parse_user_info(node) unless e.kind_of?(Nokogiri::XML::Text) || node_name == 'proxies' # There are no child elements if e.element_children.count == 0 - hash[node_name] = e.content + hash[node_name] = attribute_value(hash, node_name, e.content) elsif e.element_children.count # JASIG style extra attributes if node_name == 'attributes' diff --git a/spec/omniauth/strategies/cas/service_ticket_validator_spec.rb b/spec/omniauth/strategies/cas/service_ticket_validator_spec.rb index 8a3f452..92f40d1 100644 --- a/spec/omniauth/strategies/cas/service_ticket_validator_spec.rb +++ b/spec/omniauth/strategies/cas/service_ticket_validator_spec.rb @@ -9,6 +9,7 @@ let(:provider_options) do double('provider_options', disable_ssl_verification?: false, + merge_multivalued_attributes: false, ca_path: '/etc/ssl/certsZOMG' ) end @@ -48,8 +49,26 @@ subject { validator.user_info } - it 'parses user info from the response' do - expect(subject).to include 'user' => 'psegel' + context 'with default settings' do + it 'parses user info from the response' do + expect(subject).to include 'user' => 'psegel' + expect(subject).to include 'roles' => 'financier' + end + end + + context 'when merging multivalued attributes' do + let(:provider_options) do + double('provider_options', + disable_ssl_verification?: false, + merge_multivalued_attributes: true, + ca_path: '/etc/ssl/certsZOMG' + ) + end + + it 'parses multivalued user info from the response' do + expect(subject).to include 'user' => 'psegel' + expect(subject).to include 'roles' => %w[senator lobbyist financier] + end end end end