diff --git a/lib/omniauth/strategies/microsoft_graph.rb b/lib/omniauth/strategies/microsoft_graph.rb index 3cef1c4..665df28 100644 --- a/lib/omniauth/strategies/microsoft_graph.rb +++ b/lib/omniauth/strategies/microsoft_graph.rb @@ -6,6 +6,8 @@ class MicrosoftGraph < OmniAuth::Strategies::OAuth2 BASE_SCOPE_URL = 'https://graph.microsoft.com/' BASE_SCOPES = %w[offline_access openid email profile].freeze DEFAULT_SCOPE = 'offline_access openid email profile User.Read'.freeze + YAMMER_PROFILE_URL = 'https://www.yammer.com/api/v1/users/current.json' + MICROSOFT_GRAPH_PROFILE_URL = 'https://graph.microsoft.com/v1.0/me' option :name, :microsoft_graph @@ -64,7 +66,7 @@ def authorize_params end def raw_info - @raw_info ||= access_token.get('https://graph.microsoft.com/v1.0/me').parsed + @raw_info ||= access_token.get(profile_endpoint).parsed end def callback_url @@ -73,11 +75,27 @@ def callback_url def custom_build_access_token access_token = get_access_token(request) + # Get the profile(microsoft graph / yammer) endpoint choice based on returned bearer token + @profile_endpoint = determine_profile_endpoint(request) access_token end alias build_access_token custom_build_access_token + def profile_endpoint + @profile_endpoint ||= MICROSOFT_GRAPH_PROFILE_URL + end + + def determine_profile_endpoint(request) + scope = request&.env&.dig('omniauth.params', 'scope') + + if scope&.include?('yammer') + YAMMER_PROFILE_URL + else + MICROSOFT_GRAPH_PROFILE_URL + end + end + private def get_access_token(request) diff --git a/spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb b/spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb index b87a84c..01482d5 100644 --- a/spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb +++ b/spec/omniauth/strategies/microsoft_graph_oauth2_spec.rb @@ -457,4 +457,82 @@ end.to raise_error(OAuth2::Error) end end + + describe 'Yammer profile endpoint support' do + describe '#profile_endpoint' do + context 'when no profile endpoint is determined' do + it 'defaults to Microsoft Graph profile URL' do + expect(subject.profile_endpoint).to eq('https://graph.microsoft.com/v1.0/me') + end + end + + context 'when profile endpoint is already set' do + before { subject.instance_variable_set(:@profile_endpoint, 'https://custom.endpoint.com') } + + it 'returns the previously set endpoint' do + expect(subject.profile_endpoint).to eq('https://custom.endpoint.com') + end + end + end + + describe '#determine_profile_endpoint' do + let(:request) { double('Request', env: request_env) } + + context 'when scope includes Yammer access_as_user scope' do + let(:request_env) { { 'omniauth.params' => { 'scope' => 'https://api.yammer.com/access_as_user' } } } + + it 'returns Yammer profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://www.yammer.com/api/v1/users/current.json') + end + end + + context 'when scope includes Yammer user_impersonation scope' do + let(:request_env) { { 'omniauth.params' => { 'scope' => 'openid profile https://api.yammer.com/user_impersonation' } } } + + it 'returns Yammer profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://www.yammer.com/api/v1/users/current.json') + end + end + + context 'when scope includes Yammer scope among other scopes' do + let(:request_env) { { 'omniauth.params' => { 'scope' => 'offline_access openid email profile https://api.yammer.com/access_as_user User.Read' } } } + + it 'returns Yammer profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://www.yammer.com/api/v1/users/current.json') + end + end + + context 'when scope includes multiple Yammer scopes' do + let(:request_env) { { 'omniauth.params' => { 'scope' => 'openid profile https://api.yammer.com/access_as_user https://api.yammer.com/user_impersonation' } } } + + it 'returns Yammer profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://www.yammer.com/api/v1/users/current.json') + end + end + + context 'when scope does not include any Yammer scopes' do + let(:request_env) { { 'omniauth.params' => { 'scope' => 'openid profile User.Read' } } } + + it 'returns Microsoft Graph profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://graph.microsoft.com/v1.0/me') + end + end + + context 'when scope is nil' do + let(:request_env) { { 'omniauth.params' => { 'scope' => nil } } } + + it 'returns Microsoft Graph profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://graph.microsoft.com/v1.0/me') + end + end + + context 'when omniauth.params is nil' do + let(:request_env) { { 'omniauth.params' => nil } } + + it 'returns Microsoft Graph profile URL' do + expect(subject.determine_profile_endpoint(request)).to eq('https://graph.microsoft.com/v1.0/me') + end + end + end + end end