forked from samvera/browse-everything
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refer to samvera#418 for what is being built off of.
- Loading branch information
Showing
4 changed files
with
383 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Sharepoint Provider | ||
|
||
This provider will allow browse-everything to access a _specific_ SharePoint location | ||
|
||
First register an application on azure to give access to the relevant location | ||
|
||
https://learn.microsoft.com/en-us/graph/auth-v2-service?tabs=http (steps 1,2 and 3) | ||
|
||
To us the sharepoint provider add the following to config/browse_everything_providers.yml | ||
|
||
``` | ||
sharepoint: | ||
client_id: [MyAppClientID] | ||
client_secret: [MyAppClientSecret] | ||
tenant_id: [MyAzuerTenantID] | ||
grant_type: client_credentials | ||
scope: https://graph.microsoft.com/.default | ||
domain: mydomain.sharepoint.com | ||
site_name: [MySiteName] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
require 'oauth2' | ||
|
||
# BrowseEverything OAuth2 session for | ||
# Sharepoint provider | ||
module BrowseEverything | ||
module Auth | ||
module Sharepoint | ||
class Session | ||
|
||
OAUTH2_URLS = { | ||
:site => 'https://login.microsoftonline.com', | ||
} | ||
# :scope => "https://graph.microsoft.com/.default" | ||
|
||
def initialize(opts={}) | ||
|
||
@config = BrowseEverything.config['sharepoint'] | ||
|
||
if opts[:client_id] | ||
@oauth2_client = OAuth2::Client.new(opts[:client_id], opts[:client_secret],{:authorize_url => authorize_url, :token_url => token_url, :scope => scope}.merge!(OAUTH2_URLS.dup)) | ||
@access_token = OAuth2::AccessToken.new(@oauth2_client, opts[:access_token]) if opts[:access_token] | ||
@access_token = get_access_token if opts[:access_token].blank? | ||
@refresh_token = opts[:refresh_token] if @config[:grant_type] == 'authorization_code' | ||
# @as_user = opts[:as_user] | ||
end | ||
end | ||
|
||
def authorize_url | ||
@config['tenant_id']+"/oauth2/v2.0/authorize" | ||
end | ||
|
||
def token_url | ||
@config['tenant_id']+"/oauth2/v2.0/token" | ||
end | ||
|
||
def scope | ||
@config['scope'] | ||
end | ||
|
||
# def authorize_url(redirect_uri, state=nil) | ||
# opts = { :redirect_uri => redirect_uri } | ||
# opts[:state] = state if state | ||
# | ||
# @oauth2_client.auth_code.authorize_url(opts) | ||
# end | ||
|
||
def get_access_token(code=nil) | ||
|
||
if @config[:grant_type] == 'client_credentials' | ||
@access_token ||= @oauth2_client.client_credentials.get_token({:scope => @config[:scope]}) | ||
else | ||
# assume authorization_code grant_type..? | ||
@access_token ||= @oauth2_client.auth_code.get_token(code) | ||
end | ||
end | ||
|
||
def refresh_token(refresh_token) | ||
refresh_access_token_obj = OAuth2::AccessToken.new(@oauth2_client, @access_token.token, {'refresh_token' => refresh_token}) | ||
@access_token = refresh_access_token_obj.refresh! | ||
end | ||
|
||
def build_auth_header | ||
"BoxAuth api_key=#{@api_key}&auth_token=#{@auth_token}" | ||
end | ||
|
||
def get(url, raw=false) | ||
uri = URI.parse(url) | ||
request = Net::HTTP::Get.new( uri.request_uri ) | ||
resp = request( uri, request, raw ) | ||
end | ||
|
||
def delete(url, raw=false) | ||
uri = URI.parse(url) | ||
request = Net::HTTP::Delete.new( uri.request_uri ) | ||
resp = request( uri, request, raw ) | ||
end | ||
|
||
def request(uri, request, raw=false, retries=0) | ||
|
||
http = Net::HTTP.new(uri.host, uri.port) | ||
http.use_ssl = true | ||
#http.set_debug_output($stdout) | ||
|
||
if @access_token | ||
request.add_field('Authorization', "Bearer #{@access_token.token}") | ||
else | ||
request.add_field('Authorization', build_auth_header) | ||
end | ||
|
||
|
||
request.add_field('As-User', "#{@as_user}") if @as_user | ||
|
||
response = http.request(request) | ||
|
||
if response.is_a? Net::HTTPNotFound | ||
raise RubyBox::ObjectNotFound | ||
end | ||
|
||
# Got unauthorized (401) status, try to refresh the token | ||
if response.code.to_i == 401 and @refresh_token and retries == 0 | ||
refresh_token(@refresh_token) | ||
return request(uri, request, raw, retries + 1) | ||
end | ||
|
||
sleep(@backoff) # try not to excessively hammer API. | ||
|
||
handle_errors( response, raw ) | ||
end | ||
|
||
def do_stream(url, opts) | ||
params = { | ||
:content_length_proc => opts[:content_length_proc], | ||
:progress_proc => opts[:progress_proc] | ||
} | ||
|
||
if @access_token | ||
params['Authorization'] = "Bearer #{@access_token.token}" | ||
else | ||
params['Authorization'] = build_auth_header | ||
end | ||
|
||
params['As-User'] = @as_user if @as_user | ||
|
||
open(url, params) | ||
end | ||
|
||
def handle_errors( response, raw ) | ||
status = response.code.to_i | ||
body = response.body | ||
begin | ||
parsed_body = JSON.parse(body) | ||
rescue | ||
msg = body.nil? || body.empty? ? "no data returned" : body | ||
parsed_body = { "message" => msg } | ||
end | ||
|
||
# status is used to determine whether | ||
# we need to refresh the access token. | ||
parsed_body["status"] = status | ||
|
||
case status / 100 | ||
when 3 | ||
# 302 Found. We should return the url | ||
parsed_body["location"] = response["Location"] if status == 302 | ||
when 4 | ||
raise(RubyBox::ItemNameInUse.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "item_name_in_use" | ||
raise(RubyBox::AuthError.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "unauthorized" || status == 401 | ||
raise(RubyBox::RequestError.new(parsed_body, status, body), parsed_body["message"]) | ||
when 5 | ||
raise(RubyBox::ServerError.new(parsed_body, status, body), parsed_body["message"]) | ||
end | ||
raw ? body : parsed_body | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.