pax_global_header00006660000000000000000000000064126362751610014523gustar00rootroot0000000000000052 comment=7bd5deb0ae8734021b977c30f4e2ba5bf443c9b3 omniauth-azure-oauth2-0.0.6/000077500000000000000000000000001263627516100156765ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/.gitignore000066400000000000000000000002651263627516100176710ustar00rootroot00000000000000*.gem *.rbc .bundle .config .yardoc .ruby-gemset .ruby-version Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp omniauth-azure-oauth2-0.0.6/CHANGELOG.md000066400000000000000000000006251263627516100175120ustar00rootroot00000000000000# Version 0.0.6 * Use 'name' from Azure for name, and 'unique_name' for nickname per Auth Hash spec. Thanks @jayme-github # Version 0.0.5 * loosen jwt requirement # Version 0.0.5 * loosen jwt requirement # VERSION 0.0.4 * fix for JWT scoping, thanks @tobsher # VERSION 0.0.3 * added common endpoint and removed mandatory requirement for tenant-id * upgraded jwt # VERSION 0.0.1 * Initial buildomniauth-azure-oauth2-0.0.6/Gemfile000066400000000000000000000002201263627516100171630ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in omniauth-azure-oauth2.gemspec gemspec group :example do gem 'sinatra' endomniauth-azure-oauth2-0.0.6/LICENSE000066400000000000000000000020461263627516100167050ustar00rootroot00000000000000Copyright (c) 2014 Deltek MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.omniauth-azure-oauth2-0.0.6/README.md000066400000000000000000000103041263627516100171530ustar00rootroot00000000000000# OmniAuth Windows Azure Active Directory Strategy This gem provides a simple way to authenticate to Windows Azure Active Directory (WAAD) over OAuth2 using OmniAuth. One of the unique challenges of WAAD OAuth is that WAAD is multi tenant. Any given tenant can have multiple active directories. The CLIENT-ID, REPLY-URL and keys will be unique to the tenant/AD/application combination. This gem simply provides hooks for determining those unique values for each call. ## Installation Add this line to your application's Gemfile: ```ruby gem 'omniauth-azure-oauth2' ``` ## Usage First, you will need to add your site as an application in WAAD.: [Adding, Updating, and Removing an Application](http://msdn.microsoft.com/en-us/library/azure/dn132599.aspx) Summary: Select your Active Directory in https://manage.windowsazure.com/ of type 'Web Application'. Name, sign-on url, logo are not important. You will need the CLIENT-ID from the application configuration and you will need to generate an expiring key (aka 'client secret'). REPLY URL is the oauth redirect uri which will be the omniauth callback path https://example.com/users/auth/azure_oauth2/callback. The APP ID UI just needs to be unique to that tenant and identify your site and isn't needed to configure the gem. Permissions need Delegated Permissions to at least have "Enable sign-on and read user's profiles". Note: Seems like the terminology is still fluid, so follow the MS guidance (buwahaha) to set this up. The TenantInfo information can be a hash or class. It must provide client_id and client_secret. Optionally a domain_hint and tenant_id. For a simple single-tenant app, this could be: ```ruby use OmniAuth::Builder do provider :azure_oauth2, { client_id: ENV['AZURE_CLIENT_ID'], client_secret: ENV['AZURE_CLIENT_SECRET'], tenant_id: ENV['AZURE_TENANT_ID'] } end ``` Or the alternative format for use with [devise](https://github.com/plataformatec/devise): ```ruby config.omniauth :azure_oauth2, client_id: ENV['AZURE_CLIENT_ID'], client_secret: ENV['AZURE_CLIENT_SECRET'], tenant_id: ENV['AZURE_TENANT_ID'] ``` For multi-tenant apps where you don't know the tenant_id in advance, simply leave out the tenant_id to use the [common endpoint](http://msdn.microsoft.com/en-us/library/azure/dn645542.aspx). ```ruby use OmniAuth::Builder do provider :azure_oauth2, { client_id: ENV['AZURE_CLIENT_ID'], client_secret: ENV['AZURE_CLIENT_SECRET'] } end ``` For dynamic tenant assignment, pass a class that supports those same attributes and accepts the strategy as a parameter ```ruby class YouTenantProvider def initialize(strategy) @strategy = strategy end def client_id tenant.azure_client_id end def client_secret tenant.azure_client_secret end def tenant_id tenant.azure_tanant_id end def domain_hint tenant.azure_domain_hint end private def tenant # whatever strategy you want to figure out the right tenant from params/session @tenant ||= Customer.find(@strategy.session[:customer_id]) end end use OmniAuth::Builder do provider :azure_oauth2, YourTenantProvider end ``` ## Auth Hash Schema The following information is provided back to you for this provider: ```ruby { uid: '12345', info: { name: 'some one', first_name: 'some', last_name: 'one', email: 'someone@example.com' }, credentials: { token: 'thetoken', refresh_token: 'refresh' }, extra: { raw_info: raw_api_response } } ``` ## notes When you make a request to WAAD you must specify a resource. The gem currently assumes this is the AD identified as '00000002-0000-0000-c000-000000000000'. This can be passed in as part of the config. It currently isn't designed to be dynamic. ```ruby use OmniAuth::Builder do provider :azure_oauth2, TenantInfo, resource: 'myresource' end ``` ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Make your changes, add tests, run tests (`rake`) 4. Commit your changes and tests (`git commit -am 'Added some feature'`) 5. Push to the branch (`git push origin my-new-feature`) 6. Create new Pull Request ## Misc Run tests `bundle exec rake` Push to rubygems `bundle exec rake release`. omniauth-azure-oauth2-0.0.6/Rakefile000066400000000000000000000002231263627516100173400ustar00rootroot00000000000000require File.join('bundler', 'gem_tasks') require File.join('rspec', 'core', 'rake_task') RSpec::Core::RakeTask.new(:spec) task :default => :specomniauth-azure-oauth2-0.0.6/examples/000077500000000000000000000000001263627516100175145ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/examples/sinatra.rb000066400000000000000000000010451263627516100215020ustar00rootroot00000000000000$:.push File.dirname(__FILE__) + '/../lib' require 'omniauth-azure-oauth2' require 'sinatra' class MyAzureProvider def self.client_id ENV['AZURE_CLIENT_ID'] end def self.client_secret ENV['AZURE_CLIENT_SECRET'] end def self.tenant_id ENV['AZURE_TENANT_ID'] end end use Rack::Session::Cookie use OmniAuth::Strategies::Azure, MyAzureProvider get '/' do "Log in with Azure" end get '/auth/azure_oauth2/callback' do content_type 'text/plain' request.env['omniauth.auth'].inspect endomniauth-azure-oauth2-0.0.6/lib/000077500000000000000000000000001263627516100164445ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/lib/omniauth-azure-oauth2.rb000066400000000000000000000000551263627516100231410ustar00rootroot00000000000000require File.join('omniauth', 'azure_oauth2')omniauth-azure-oauth2-0.0.6/lib/omniauth/000077500000000000000000000000001263627516100202705ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/lib/omniauth/azure_oauth2.rb000066400000000000000000000000731263627516100232250ustar00rootroot00000000000000require File.join('omniauth', 'strategies', 'azure_oauth2')omniauth-azure-oauth2-0.0.6/lib/omniauth/azure_oauth2/000077500000000000000000000000001263627516100227005ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/lib/omniauth/azure_oauth2/version.rb000066400000000000000000000001051263627516100247060ustar00rootroot00000000000000module OmniAuth module AzureOauth2 VERSION = "0.0.6" end end omniauth-azure-oauth2-0.0.6/lib/omniauth/strategies/000077500000000000000000000000001263627516100224425ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/lib/omniauth/strategies/azure_oauth2.rb000066400000000000000000000035251263627516100254040ustar00rootroot00000000000000require 'omniauth/strategies/oauth2' require 'jwt' module OmniAuth module Strategies class AzureOauth2 < OmniAuth::Strategies::OAuth2 BASE_AZURE_URL = 'https://login.windows.net' option :name, 'azure_oauth2' option :tenant_provider, nil # AD resource identifier option :resource, '00000002-0000-0000-c000-000000000000' # tenant_provider must return client_id, client_secret and optionally tenant_id args [:tenant_provider] def client if options.tenant_provider provider = options.tenant_provider.new(self) else provider = options # if pass has to config, get mapped right on to ptions end options.client_id = provider.client_id options.client_secret = provider.client_secret options.tenant_id = provider.respond_to?(:tenant_id) ? provider.tenant_id : 'common' options.authorize_params.domain_hint = provider.domain_hint if provider.respond_to?(:domain_hint) && provider.domain_hint options.client_options.authorize_url = "#{BASE_AZURE_URL}/#{options.tenant_id}/oauth2/authorize" options.client_options.token_url = "#{BASE_AZURE_URL}/#{options.tenant_id}/oauth2/token" options.token_params.resource = options.resource super end uid { raw_info['sub'] } info do { name: raw_info['name'], nickname: raw_info['unique_name'], first_name: raw_info['given_name'], last_name: raw_info['family_name'], email: raw_info['email'] || raw_info['upn'], oid: raw_info['oid'] } end def raw_info # it's all here in JWT http://msdn.microsoft.com/en-us/library/azure/dn195587.aspx @raw_info ||= ::JWT.decode(access_token.token, nil, false).first end end end end omniauth-azure-oauth2-0.0.6/omniauth-azure-oauth2.gemspec000066400000000000000000000020671263627516100234200ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require File.expand_path(File.join('..', 'lib', 'omniauth', 'azure_oauth2', 'version'), __FILE__) Gem::Specification.new do |gem| gem.authors = ["Mark Nadig"] gem.email = ["mark@nadigs.net"] gem.description = %q{An Windows Azure Active Directory OAuth2 strategy for OmniAuth} gem.summary = %q{An Windows Azure Active Directory OAuth2 strategy for OmniAuth} gem.homepage = "https://github.com/KonaTeam/omniauth-azure-oauth2" gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- {spec}/*`.split("\n") gem.name = "omniauth-azure-oauth2" gem.require_paths = ["lib"] gem.version = OmniAuth::AzureOauth2::VERSION gem.license = "MIT" gem.add_dependency 'omniauth', '~> 1.0' gem.add_dependency 'jwt', '~> 1.0' gem.add_runtime_dependency 'omniauth-oauth2', '~> 1.1' gem.add_development_dependency 'rspec', '>= 2.14.0' gem.add_development_dependency 'rake' end omniauth-azure-oauth2-0.0.6/spec/000077500000000000000000000000001263627516100166305ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/spec/omniauth/000077500000000000000000000000001263627516100204545ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/spec/omniauth/strategies/000077500000000000000000000000001263627516100226265ustar00rootroot00000000000000omniauth-azure-oauth2-0.0.6/spec/omniauth/strategies/azure_oauth2_spec.rb000066400000000000000000000111551263627516100266000ustar00rootroot00000000000000require 'spec_helper' require 'omniauth-azure-oauth2' module OmniAuth module Strategies module JWT; end end end describe OmniAuth::Strategies::AzureOauth2 do let(:request) { double('Request', :params => {}, :cookies => {}, :env => {}) } let(:app) { lambda do [200, {}, ["Hello."]] end } before do OmniAuth.config.test_mode = true end after do OmniAuth.config.test_mode = false end describe 'static configuration' do let(:options) { @options || {} } subject do OmniAuth::Strategies::AzureOauth2.new(app, {client_id: 'id', client_secret: 'secret', tenant_id: 'tenant'}.merge(options)) end describe '#client' do it 'has correct authorize url' do expect(subject.client.options[:authorize_url]).to eql('https://login.windows.net/tenant/oauth2/authorize') end it 'has correct authorize params' do subject.client expect(subject.authorize_params[:domain_hint]).to be_nil end it 'has correct token url' do expect(subject.client.options[:token_url]).to eql('https://login.windows.net/tenant/oauth2/token') end it 'has correct token params' do subject.client expect(subject.token_params[:resource]).to eql('00000002-0000-0000-c000-000000000000') end describe "overrides" do it 'should override domain_hint' do @options = {domain_hint: 'hint'} subject.client expect(subject.authorize_params[:domain_hint]).to eql('hint') end end end end describe 'static common configuration' do let(:options) { @options || {} } subject do OmniAuth::Strategies::AzureOauth2.new(app, {client_id: 'id', client_secret: 'secret'}.merge(options)) end describe '#client' do it 'has correct authorize url' do expect(subject.client.options[:authorize_url]).to eql('https://login.windows.net/common/oauth2/authorize') end it 'has correct token url' do expect(subject.client.options[:token_url]).to eql('https://login.windows.net/common/oauth2/token') end end end describe 'dynamic configuration' do let(:provider_klass) { Class.new { def initialize(strategy) end def client_id 'id' end def client_secret 'secret' end def tenant_id 'tenant' end } } subject do OmniAuth::Strategies::AzureOauth2.new(app, provider_klass) end describe '#client' do it 'has correct authorize url' do expect(subject.client.options[:authorize_url]).to eql('https://login.windows.net/tenant/oauth2/authorize') end it 'has correct authorize params' do subject.client expect(subject.authorize_params[:domain_hint]).to be_nil end it 'has correct token url' do expect(subject.client.options[:token_url]).to eql('https://login.windows.net/tenant/oauth2/token') end it 'has correct token params' do subject.client expect(subject.token_params[:resource]).to eql('00000002-0000-0000-c000-000000000000') end # todo: how to get this working? # describe "overrides" do # it 'should override domain_hint' do # provider_klass.domain_hint = 'hint' # subject.client # expect(subject.authorize_params[:domain_hint]).to eql('hint') # end # end end end describe 'dynamic common configuration' do let(:provider_klass) { Class.new { def initialize(strategy) end def client_id 'id' end def client_secret 'secret' end } } subject do OmniAuth::Strategies::AzureOauth2.new(app, provider_klass) end describe '#client' do it 'has correct authorize url' do expect(subject.client.options[:authorize_url]).to eql('https://login.windows.net/common/oauth2/authorize') end it 'has correct token url' do expect(subject.client.options[:token_url]).to eql('https://login.windows.net/common/oauth2/token') end end end describe "raw_info" do subject do OmniAuth::Strategies::AzureOauth2.new(app, {client_id: 'id', client_secret: 'secret'}) end let(:token) do JWT.encode({"some" => "payload"}, "secret") end let(:access_token) do double(:token => token) end before :each do allow(subject).to receive(:access_token) { access_token } end it "does not clash if JWT strategy is used" do expect do subject.info end.to_not raise_error end end end omniauth-azure-oauth2-0.0.6/spec/spec_helper.rb000066400000000000000000000000651263627516100214470ustar00rootroot00000000000000require File.join('bundler', 'setup') require 'rspec'