Skip to content

Commit

Permalink
Authentication for Ruby (microsoft#1760)
Browse files Browse the repository at this point in the history
* Implemented allowedhostsvalidator class and made a couple changes to base bearer file

* Small fix to line 23

* Final commit for this branch

* auth commit 😝

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update to gemfile

* update

* Gemfile update.

* update

* update

* update

* update

* Updated Changelog to Reflect Ruby Auth Additions

* Commiting some of the changes requested by Philip

* Refactoring and Reorganization of Authentication

* Changed access token provider constructor

* Fixing the require statements in access token p

* Deleting outdated tests

* Changes/update to Access Token Provider Interface

* Updating changelog, gemspec, and readme

* Removing include statement

* Update abstractions/ruby/microsoft_kiota_abstractions/README.md

Co-authored-by: Vincent Biret <vibiret@microsoft.com>

* Updating Custom Context

* Update abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/authentication/allowed_hosts_validator.rb

Co-authored-by: Philip Gichuhi <pgichuhi@microsoft.com>

* Implementing some requested changes

* Updates to tests to reflect valid host hash

* Changing Package Name

* - adds a workflow for ruby authentication package

* - fixes link to badge for ruby authentication package

* Update authentication-ruby-oauth.yml

* Deleting the Azure Folder

* Adding Auth folder with the name oauth

* Update authentication/ruby/oauth/microsoft_kiota_authentication_oauth/lib/microsoft_kiota_authentication_oauth/oauth_access_token_provider.rb

Co-authored-by: Philip Gichuhi <pgichuhi@microsoft.com>

* Updating scopes on authcode flow

* Updating oauth access token provider

* Updating contexts

* Update to mimic interfaces in custom oauth flow

Co-authored-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Philip Gichuhi <pgichuhi@microsoft.com>
  • Loading branch information
3 people authored Aug 18, 2022
1 parent c261e9d commit f9c5778
Show file tree
Hide file tree
Showing 28 changed files with 829 additions and 35 deletions.
104 changes: 104 additions & 0 deletions .github/workflows/authentication-ruby-oauth.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Ruby serialization

on:
workflow_dispatch:
push:
branches: [ main ]
paths: ['authentication/ruby/**', '.github/workflows/**']
pull_request:
paths: ['authentication/ruby/**', '.github/workflows/**']

jobs:
build:
env:
relativePath: ./authentication/ruby/oauth/microsoft_kiota_authentication_oauth
BUNDLE_HTTPS://RUBYGEMS__PKG__GITHUB__COM/MICROSOFT/: "${{ secrets.PUBLISH_GH_USERNAME }}:${{ secrets.PUBLISH_GH_TOKEN }}"
BUNDLE_RUBYGEMS__PKG__GITHUB__COM: "${{ secrets.PUBLISH_GH_USERNAME }}:${{ secrets.PUBLISH_GH_TOKEN }}" #needed for jruby-head
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
# Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
ruby-version: [2.5, 2.6, 2.7, '3.0', head, jruby, jruby-head, truffleruby, truffleruby-head]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
bundler: 'latest'
cache-version: 1
working-directory: ${{ env.relativePath }}
- name: Run tests
run: bundle exec rake
working-directory: ${{ env.relativePath }}
- name: Upload artifacts for ruby version 3 and ubuntu
if: ${{ matrix.os == 'ubuntu-latest' && matrix.ruby-version == '3.0'}}
uses: actions/upload-artifact@v3
with:
name: drop
path: |
${{ env.relativePath }}/Gemfile.lock
${{ env.relativePath }}/README.md
deploy:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
environment:
name: staging_feeds
runs-on: ubuntu-latest
env:
relativePath: ./authentication/ruby/oauth/microsoft_kiota_authentication_oauth
BUNDLE_HTTPS://RUBYGEMS__PKG__GITHUB__COM/MICROSOFT/: "${{ secrets.PUBLISH_GH_USERNAME }}:${{ secrets.PUBLISH_GH_TOKEN }}"
needs: [build]
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
# Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
ruby-version: '3.0'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
bundler: 'latest'
cache-version: 1
working-directory: ${{ env.relativePath }}
- run: bundle exec rake
working-directory: ${{ env.relativePath }}
- name: Publish to GPR
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build *.gemspec
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
working-directory: ${{ env.relativePath }}
env:
GEM_HOST_API_KEY: "Bearer ${{secrets.PUBLISH_GH_TOKEN}}"
OWNER: ${{ github.repository_owner }}
# deploy_prod:
# if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
# environment:
# name: production_feeds
# runs-on: ubuntu-latest
# env:
# relativePath: ./authentication/ruby/oauth/microsoft_kiota_authentication_oauth
# BUNDLE_HTTPS://RUBYGEMS__PKG__GITHUB__COM/MICROSOFT/: "${{ secrets.PUBLISH_GH_USERNAME }}:${{ secrets.PUBLISH_GH_TOKEN }}"
# needs: [build]
# steps:
# - uses: actions/checkout@v3
# - uses: ruby/setup-ruby@v1
# with:
# # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
# ruby-version: '3.0'
# bundler-cache: true # runs 'bundle install' and caches installed gems automatically
# - run: bundle exec rake
# - name: Publish to RubyGems
# run: |
# mkdir -p $HOME/.gem
# touch $HOME/.gem/credentials
# chmod 0600 $HOME/.gem/credentials
# printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
# gem build *.gemspec
# gem push *.gem
# env:
# GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}" TODO: Token for rubyGems.org

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adds python code generation support. [#1200](https://github.com/microsoft/kiota/issues/163)
- Added native type support for Duration, Time Only, and Date Only in Ruby. [#1644](https://github.com/microsoft/kiota/issues/1644)
- Added a `--additional-data` argument to generate the AdditionalData properties [#1772](https://github.com/microsoft/kiota/issues/1772)
- Added CAE infrastructure in Ruby by adding an `--additional-properties` parameter to the authenticate method of AuthenticationProvider, the get access token method of the AccessTokenProvider in Ruby. [#1643](https://github.com/microsoft/kiota/issues/1643)
- Added Kiota authentication library for Ruby. [#421](https://github.com/microsoft/kiota/issues/421)

### Changed

Expand All @@ -32,8 +34,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed an issue where duplicate 'require' statements are generated for inner classes in the middle of the file (Ruby). [#1649](https://github.com/microsoft/kiota/issues/1649)
- Split parsable interface and additional property/data interface in Ruby. [#1654](https://github.com/microsoft/kiota/issues/1654)
- Changed format of datetimes in Go to be converted to ISO 8601 by default when place in path parameters(Go)
- Defined the Access Token Provider Interface for Ruby authentication. [#1638](https://github.com/microsoft/kiota/issues/1638)
- Reduce code verbosity on Go Getters and Setters. [G0#26][https://github.com/microsoftgraph/msgraph-sdk-go-core/issues/26]


## [0.3.0] - 2022-07-08

### Added
Expand All @@ -46,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for vendor specific content types(PHP) [#1464](https://github.com/microsoft/kiota/issues/1464)
- Added support for accept request header (PHP) [#1616](https://github.com/microsoft/kiota/issues/1616)
- Added Getting Started steps for PHP. [#1642](https://github.com/microsoft/kiota/pull/1642)
- Defined the Access Token Provider interface (Ruby) [#1638](https://github.com/microsoft/kiota/issues/1638)
- Added Continuous Access Evalution infrastructure (Ruby) [#1643](https://github.com/microsoft/kiota/issues/1643)

### Changed

Expand Down
3 changes: 0 additions & 3 deletions abstractions/ruby/microsoft_kiota_abstractions/.rspec

This file was deleted.

2 changes: 1 addition & 1 deletion abstractions/ruby/microsoft_kiota_abstractions/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ gem 'concurrent-ruby', '~> 1.1', '>= 1.1.9'

gem 'addressable', '~> 2.7', '>= 2.7.0'

gem 'iso8601', '~> 0.13.0'
gem 'iso8601', '~> 0.13.0'
2 changes: 1 addition & 1 deletion abstractions/ruby/microsoft_kiota_abstractions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bundle install
Or install it yourself as:

```shell
gem install microsoft_kiota_abstractions --version "0.1.11" --source "https://{USERNAME}{PASSWORD/TOKEN}rubygems.pkg.github.com/microsoft"
gem install microsoft_kiota_abstractions --version "0.2.0" --source "https://{USERNAME}{PASSWORD/TOKEN}rubygems.pkg.github.com/microsoft"
```

## Contributing
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require 'concurrent'
require_relative 'allowed_hosts_validator'

module MicrosoftKiotaAbstractions
# Access Token Provider Module implementation
module AccessTokenProvider
# This function obtains the authorization token.
# :params
# uri: a string containing the uri
# additional_params: hash of symbols to string values, ie { response_mode: 'fragment', prompt: 'login' }
# default is empty hash
def get_authorization_token(uri, additional_properties = {})
raise NotImplementedError.new
end

attr_accessor :scopes, :host_validator

end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'uri'

module MicrosoftKiotaAbstractions
# Maintains a list of valid hosts and allows authentication providers to check whether
# a host is valid before authenticating a request
class AllowedHostsValidator
# creates a new AllocatedHostsValidator with provided values
def initialize(allowed_hosts)
@allowed_hosts = {}
allowed_hosts.each { |host| @allowed_hosts[host.downcase] = true }
end

# sets the list of valid hosts with provided value (val)
def allowed_hosts=(val)
@allowed_hosts = {}
val.each { |host| @allowed_hosts[host.downcase] = true }
end

# checks whether the provided host is valid
def url_host_valid?(url)
return false unless url =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]

return true if @allowed_hosts.empty?

parsed_url = URI(url)

return false if parsed_url.host.nil?

@allowed_hosts.key? parsed_url.host.downcase
end

# gets the list of valid hosts
attr_reader :allowed_hosts
end
end
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
module MicrosoftKiotaAbstractions
module AuthenticationProvider

def authenticate_request(request)
def authenticate_request(request, additional_properties = {})
raise NotImplementedError.new
end

end
end
end
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
# frozen_string_literal: true

require 'concurrent'
require_relative './authentication_provider'
require_relative './access_token_provider'

module MicrosoftKiotaAbstractions
class BaseBearerTokenAuthenticationProvider
# Provides a base class for implementing AuthenticationProvider for Bearer token scheme
class BaseBearerTokenAuthenticationProvider
include MicrosoftKiotaAbstractions::AccessTokenProvider
include MicrosoftKiotaAbstractions::AuthenticationProvider
include Concurrent::Async
def initialize(access_token_provider)
raise StandardError, 'access_token_provider parameter cannot be nil' if access_token_provider.nil?

@access_token_provider = access_token_provider
end

AUTHORIZATION_HEADER_KEY = 'Authorization'
def authenticate_request(request)
if !request
raise StandardError, 'request cannot be null'
end
if !request.headers.has_key?(AUTHORIZATION_HEADER_KEY)
token = self.get_authorization_token(request)
if !token
raise StandardError, 'Could not get an authorization token'
end
request.headers[AUTHORIZATION_HEADER_KEY] = 'Bearer ' + token
end
end
def authenticate_request(request, additional_properties)
raise StandardError, 'Request cannot be null' if request.nil?
return if request.headers.key?(AUTHORIZATION_HEADER_KEY)

token = @access_token_provider.get_authorization_token(request, additional_properties)

def get_authorization_token(request)
raise NotImplementedError, 'get_authorization_token must be implemented'
request.headers[AUTHORIZATION_HEADER_KEY] = "Bearer #{token}" unless token.nil?
end
end
end

Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,6 @@
expect(token_provider).not_to be nil
end

it "creates a bearer token provider" do
token_provider = MicrosoftKiotaAbstractions::BaseBearerTokenAuthenticationProvider.new()
expect(token_provider).not_to be nil
end

it "throws if the token method is not implemented" do
token_provider = MicrosoftKiotaAbstractions::BaseBearerTokenAuthenticationProvider.new()
expect { token_provider.authenticate_request(MicrosoftKiotaAbstractions::RequestInformation.new()) }.to raise_error(NotImplementedError)
end

it "returns the raw URI when set via setter" do
request_obj = MicrosoftKiotaAbstractions::RequestInformation.new
request_obj.path_parameters["term"] = "search"
Expand Down Expand Up @@ -91,4 +81,39 @@
time2 = MicrosoftKiotaAbstractions::ISODuration.new({ :years => 4, :months => 2, :hours => 2 } )
expect(time1).to eq(time2)
end

it 'initializes empty allowed hosts properly' do
ahv = MicrosoftKiotaAbstractions::AllowedHostsValidator.new([])
expect(ahv.allowed_hosts).to eq({})
end

it 'initializes non-empty/cased allowed hosts properly' do
ahv = MicrosoftKiotaAbstractions::AllowedHostsValidator.new(['microsoft.com', 'Graph.microsoft.com', 'DOD-graph.microsoft.us'])
valid_hosts = ahv.allowed_hosts
expect(valid_hosts).to eq({'microsoft.com' => true, 'graph.microsoft.com' => true, 'dod-graph.microsoft.us' => true})
end

it 'tests the setter for allowed hosts on allowed hosts validator' do
ahv = MicrosoftKiotaAbstractions::AllowedHostsValidator.new(['microsoft.com', 'Graph.microsoft.com', 'DOD-graph.microsoft.us'])
ahv.allowed_hosts = ['MICROSOFT.com', 'GRAPH.microsoft.COM', 'DOD-graph.microsoft.us', 'graph.microsoft.de']
expect(ahv.allowed_hosts).to eq({'microsoft.com' => true, 'graph.microsoft.com' => true, 'dod-graph.microsoft.us' => true, 'graph.microsoft.de' => true})
end

it 'tests url_host_valid? method on malformed and valid urls' do
ahv = MicrosoftKiotaAbstractions::AllowedHostsValidator.new(['www.google.com', 'example.com', 'Graph.microsoft.com',
'DOD-graph.microsoft.us', "cool/groovy/art"])
url1 = ahv.url_host_valid?("https://www.google.com")
url2 = ahv.url_host_valid?("htts://google.com")
url3 = ahv.url_host_valid?("cool/groovy/art")
url4 = ahv.url_host_valid?("http://example.com")
url5 = ahv.url_host_valid?('https%3A%2F%2Fwww.example.com')
url6 = ahv.url_host_valid?('%3A%2F%2F')
expect(url1).to eq(true)
expect(url2).to eq(false)
expect(url3).to eq(false)
expect(url4).to eq(true)
expect(url5).to eq(false)
expect(url5).to eq(false)
expect(url6).to eq(false)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# rspec failure tracking
.rspec_status
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

source 'https://rubygems.org'

# Specify your gem's dependencies in microsoft_kiota_authentication.gemspec
gemspec

# git_source(:github) { |repo_name| "https://rubygems.pkg.github.com/microsoft" }

source "https://rubygems.pkg.github.com/microsoft" do
gem "microsoft_kiota_abstractions", "0.2.0"
end

gem 'rake', '~> 13.0'

gem 'rspec', '~> 3.0'

gem 'rubocop', require: false

gem 'concurrent-ruby', '~> 1.1', '>= 1.1.9'

gem 'addressable', '~> 2.7', '>= 2.7.0'

gem "oauth2", "~> 2.0"
Loading

0 comments on commit f9c5778

Please sign in to comment.