-
Notifications
You must be signed in to change notification settings - Fork 20
Support CAS Protocol 3.0 attributes #2
base: 0-3-stable
Are you sure you want to change the base?
Conversation
* general code cleanup * look for attributes element, new in CAS Protocol 3.0 * if found, add those attributes into the user_info hash
This omniauth-cas module (built for omniauth-1.0) had already integrated this change from the original (omniauth 0.3 code that is in use here), so i'm i'm just going to port it over. This work was done in these commits: dlindahl/omniauth-cas@8de378c , dlindahl/omniauth-cas@8ec97af |
This model is of a CAS Protocol 3.0-style authenticationSuccess response that includes additional attributes. Details on the format can be found here: https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#attributes-cas-30
- abstract user_info a bit with raw_info - build out the proper hash for the omniauth schema requirements - expose uid in a managed way
Note, the CAS success mock defined dlindahl/omniauth-cas@8ec97af and previously in our test suite is not valid schema. The only valid elements under success (per the schema linked above for 2.0) was <xs:complexType name="AuthenticationSuccessType">
<xs:sequence>
<xs:element name="user" type="xs:string"/>
<xs:element name="proxyGrantingTicket" type="xs:string" minOccurs="0"/>
<xs:element name="proxies" type="cas:ProxiesType" minOccurs="0"/>
</xs:sequence>
</xs:complexType> I'm updating the Protocol 2.0 tests (and spec/mock) to reflect this. |
cc/ @github/platform-iam I believe this PR would fall under your purview. I'm pretty satisfied with the code as is, but can't figure out how we expect rspec to run appropriately. I'd feel 💯% better sending you a PR with passing tests, but am about at the end of my capability. |
{}.tap do |hash| | ||
node.children.each do |e| | ||
node_name = e.name.sub(/^cas:/, '') | ||
unless e.kind_of?(Nokogiri::XML::Text) || node_name == 'proxies' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice cleanup @jbjonesjr! If we wanted to be even nitpickier, maybe use a next if
here instead of the unless
block for readability?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davesims I copied this method from the upstream code. I have no clue as to our plan to ever sync with upstream again, so am not sure how much we care about being compatible. Thoughts?
Thanks for this @jbjonesjr! I took a quick first pass on it, I'll do more thorough 👀 later this week. Looks great so far. |
attr_accessor :raw_info | ||
alias_method :user_info, :raw_info | ||
|
||
option :uid_key, 'user' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the option
method is available in modern implementations of OmniAuth::Strategy
, it is not available in the github/omniauth version
Need to revert back to a regular attr_accessor
with a default.
So I figured out how to run the tests, am working my way through confirming that this actually works. Will commit and make a comment when ready to go again |
Finished in 0.12449 seconds
18 examples, 1 failure
Failed examples:
rspec ./spec/omniauth/strategies/cas_spec.rb:129 # OmniAuth::Strategies::CAS GET /auth/cas/callback with a valid ticket and gzipped response from the server on ruby >1.8 should call through to the master app when response is gzipped Got almost all the tests passing (pretty sure the failing tests failed before I started this experiment). I need to now go back and make sure this is compatible with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
annotated my changes for this codebase
|
||
@uid_key = 'user' | ||
|
||
def userHash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add fields defined in the omniauth user_info hash. support multiple formats that it can be shared via
def initialize(app, options = {}, &block) | ||
super(app, options[:name] || :cas, options.dup, &block) | ||
@configuration = OmniAuth::Strategies::CAS::Configuration.new(options) | ||
@configuration = OmniAuth::Strategies::CAS::Configuration.new(options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just whitespace change
@ticket = request.params['ticket'] | ||
return fail!(:no_ticket, 'No CAS Ticket') unless @ticket | ||
|
||
self.raw_info = ServiceTicketValidator.new(@configuration, callback_url, @ticket).user_info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use the raw_info accessor, also chain methods for readability
super | ||
end | ||
|
||
def auth_hash | ||
OmniAuth::Utils.deep_merge(super, { | ||
'uid' => @user_info.delete('user'), | ||
'extra' => @user_info | ||
'uid' => @raw_info['user'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
configure omniauth object as defined in Auth Hash Schema
|
||
# Deletes Hash pairs with `nil` values. | ||
# From https://github.com/mkdynamic/omniauth-facebook/blob/972ed5e3456bcaed7df1f55efd7c05c216c8f48e/lib/omniauth/strategies/facebook.rb#L122-127 | ||
def prune!(hash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean up nil/null values
to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'cas_success.xml'))) | ||
get '/auth/cas/callback?ticket=593af' | ||
end | ||
shared_examples :successful_validation do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
upstream tests are a bit cleaner and easier to follow.
get "/auth/cas/callback?ticket=593af&url=#{return_url}" | ||
end | ||
|
||
it 'should strip the ticket parameter from the callback URL before sending it to the CAS server' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most of these tests are from upstream, but some of my own intepretation based on our sample success criteria
let(:return_url) { 'http://127.0.0.10/?some=parameter' } | ||
|
||
|
||
context 'cas-protocol-2.0' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
support the two different protocols under test
end | ||
stub_request(:get, /^https:\/\/cas.example.org(:443)?\/serviceValidate\?([^&]+&)?ticket=593af/). | ||
stub_request(:get, /^http(s)?:\/\/cas.example.org(:8080)?\/serviceValidate\?([^&]+&)?ticket=593af/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above.
context 'cas-protocol-3.0' do | ||
let(:xml_file_name) { 'cas_success_3.0.xml' } | ||
it_behaves_like :successful_validation | ||
end | ||
end | ||
|
||
unless RUBY_VERSION =~ /^1\.8\.\d$/ | ||
describe 'GET /auth/cas/callback with a valid ticket and gzipped response from the server on ruby >1.8' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: this test fails on my branch, and on the branch i branched from.
¯_(ツ)_/¯
OK 👌 . I've taken advantage of the new code review functionality to annotate the work that I have performed in this PR. I'm happy to answer any questions that anyone may have. cc/ @sbryant as some folks thought you might be an owner of this sort of thing. |
CAS 2.0 just returned username and ticket in the authenticationSuccess message
CAS Protocol 3.0 supports additional attributes
This pull request updates the parsing of the
<authenticationSuccess>
element to include attributes.Actions