From 7bd05530ebfae164ebc453d62310351289dbb4e2 Mon Sep 17 00:00:00 2001 From: TaterLi Date: Tue, 23 Jun 2020 15:00:44 +0800 Subject: [PATCH] onedrive: add support for no admin mode Add tenant_url configuration option for accessing OneDrive/SharePoint without admin privileges. When tenant_url is set, rclone uses the SharePoint v2.0 API endpoint instead of the standard Microsoft Graph API. Co-Authored-By: KyokoMiki <161209740+kyokomiki@users.noreply.github.com> --- backend/onedrive/onedrive.go | 43 ++++++++++++++++++++++++++++++++++-- docs/content/onedrive.md | 35 +++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/backend/onedrive/onedrive.go b/backend/onedrive/onedrive.go index c0662f5bd..35fada17e 100644 --- a/backend/onedrive/onedrive.go +++ b/backend/onedrive/onedrive.go @@ -154,6 +154,21 @@ See: https://github.com/rclone/rclone/issues/1716 `, Default: fs.SizeSuffix(-1), Advanced: true, + }, { + Name: "tenant_url", + Help: `The tenant URL for non-admin OneDrive access. + +Set this to your SharePoint tenant URL to use the SharePoint v2.0 API +endpoint instead of the standard Microsoft Graph API. This allows +accessing business OneDrive without admin consent. + +The URL can be found in your browser's developer tools by searching +for "driveAccessToken" in the network requests. Look for the +".driveUrl" field which contains the tenant URL and drive ID. + +Example: https://your-tenant.sharepoint.com/_api`, + Default: "", + Advanced: true, }, { Name: "chunk_size", Help: `Chunk size to upload files with - must be multiple of 320k (327,680 bytes). @@ -471,7 +486,15 @@ isn't always desirable to set the permissions from the metadata. // Get the region and graphURL from the config func getRegionURL(m configmap.Mapper) (region, graphURL string) { region, _ = m.Get("region") + graphURL = graphAPIEndpoint[region] + "/v1.0" + + // Check if tenant_url is provided for non-admin mode + tenantURL, _ := m.Get("tenant_url") + if tenantURL != "" { + graphURL = tenantURL + "/v2.0" + } + return region, graphURL } @@ -764,6 +787,7 @@ type Options struct { Region string `config:"region"` UploadCutoff fs.SizeSuffix `config:"upload_cutoff"` ChunkSize fs.SizeSuffix `config:"chunk_size"` + TenantURL string `config:"tenant_url"` DriveID string `config:"drive_id"` DriveType string `config:"drive_type"` RootFolderID string `config:"root_folder_id"` @@ -1070,6 +1094,10 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e rootURL := graphAPIEndpoint[opt.Region] + "/v1.0" + "/drives/" + opt.DriveID + if opt.TenantURL != "" { + rootURL = opt.TenantURL + "/v2.0" + "/drives/" + opt.DriveID + } + oauthConfig, err := makeOauthConfig(ctx, opt) if err != nil { return nil, err @@ -2738,7 +2766,13 @@ func (o *Object) ID() string { // and returns itemID, driveID, rootURL. // Such a normalized ID can come from (*Item).GetID() func (f *Fs) parseNormalizedID(ID string) (string, string, string) { - rootURL := graphAPIEndpoint[f.opt.Region] + "/v1.0/drives" + var rootURL string + if f.opt.TenantURL != "" { + rootURL = f.opt.TenantURL + "/v2.0/drives" + } else { + rootURL = graphAPIEndpoint[f.opt.Region] + "/v1.0/drives" + } + if strings.Contains(ID, "#") { s := strings.Split(ID, "#") return s[1], s[0], rootURL @@ -2933,7 +2967,12 @@ func (f *Fs) changeNotifyNextChange(ctx context.Context, token string) (delta ap } func (f *Fs) buildDriveDeltaOpts(token string) rest.Opts { - rootURL := graphAPIEndpoint[f.opt.Region] + "/v1.0/drives" + var rootURL string + if f.opt.TenantURL != "" { + rootURL = f.opt.TenantURL + "/v2.0/drives" + } else { + rootURL = graphAPIEndpoint[f.opt.Region] + "/v1.0/drives" + } return rest.Opts{ Method: "GET", diff --git a/docs/content/onedrive.md b/docs/content/onedrive.md index 806e76d0b..f97b07df6 100644 --- a/docs/content/onedrive.md +++ b/docs/content/onedrive.md @@ -237,6 +237,41 @@ credentials. anyone with the *Client ID* and *Client Secret* can access your OneDrive files. Take care to safeguard these credentials. +### Non-admin access to Business OneDrive + +If you do not have admin access to your organization's OneDrive for +Business, you can still connect by manually providing the SharePoint +tenant URL and drive ID. This works by overriding the base API URL +from the standard Microsoft Graph endpoint to the SharePoint v2.0 +endpoint. + +#### Steps to manually obtain credentials + +1. Open your browser and navigate to `https://[your-tenant].sharepoint.com/` +2. Open Developer Tools (press F12) and go to the **Network** tab. +3. Search for `driveAccessToken` in the network requests. +4. Extract the following information from the response: + ```json + ".driveUrl": "{tenant_url}/v2.0/drives/{drive_id}", + ".driveAccessToken": "access_token={access_token}" + ``` + +#### Rclone configuration + +Use the extracted values to configure your remote: + +```ini +type = onedrive +token = {"access_token":"{access_token}","token_type":"Bearer","refresh_token":"","expiry":"2045-12-31T23:59:59Z"} +drive_id = {drive_id} +tenant_url = {tenant_url} +drive_type = business +``` + +Since the exact expiry time cannot be determined from web traffic, +set the expiry to a future date. Note that the token will eventually +expire and you will need to repeat the process to obtain a new one. + ### Modification times and hashes OneDrive allows modification times to be set on objects accurate to 1