onedrive: Removed second browser authentication and enabled headless mode #254

This commit is contained in:
Oliver Heyme 2017-09-06 17:19:52 +02:00 committed by Nick Craig-Wood
parent 113f43ec42
commit f91f89d409
2 changed files with 77 additions and 21 deletions

View File

@ -114,7 +114,7 @@ To copy a local directory to an OneDrive directory called backup
### OneDrive for Business ###
There is experimental support for OneDrive for Business.
There is additional support for OneDrive for Business.
Select "b" when ask
```
Choose OneDrive account type?
@ -124,10 +124,8 @@ b) Business
p) Personal
b/p>
```
After that rclone requires two authentications. First to authenicate your account
and second to get the final token to access your companies resources.
Headless authentication is not working at the moment.
After that rclone requires an authentication of your account. The application will first authenticate your account, then query the OneDrive resource URL
and do a second (silent) authentication for this resource URL.
### Modified time and hashes ###

View File

@ -91,9 +91,16 @@ func init() {
log.Fatalf("Failed to configure token: %v", err)
}
} else {
err := oauthutil.Config("onedrivebusiness", name, oauthBusinessConfig, oauthBusinessResource)
err := oauthutil.Config("onedrive", name, oauthBusinessConfig, oauthBusinessResource)
if err != nil {
log.Fatalf("Failed to configure token: %v", err)
return
}
// Are we running headless?
if fs.ConfigFileGet(name, fs.ConfigAutomatic) != "" {
// Yes, okay we are done
return
}
type serviceResource struct {
@ -108,43 +115,94 @@ func init() {
oAuthClient, _, err := oauthutil.NewClient(name, oauthBusinessConfig)
if err != nil {
log.Fatalf("Failed to configure OneDrive: %v", err)
return
}
srv := rest.NewClient(oAuthClient).SetRoot(discoveryServiceURL)
srv := rest.NewClient(oAuthClient)
opts := rest.Opts{
Method: "GET",
Path: "/v2.0/me/services",
Method: "GET",
RootURL: discoveryServiceURL,
Path: "/v2.0/me/services",
}
services := serviceResponse{}
resp, err := srv.CallJSON(&opts, nil, &services)
if err != nil {
log.Fatalf("Failed to query available services: %v", err)
fs.Errorf(nil, "Failed to query available services: %v", err)
return
}
if resp.StatusCode != 200 {
log.Fatalf("Failed to query available services: Got HTTP error code %d", resp.StatusCode)
fs.Errorf(nil, "Failed to query available services: Got HTTP error code %d", resp.StatusCode)
return
}
foundService := false
foundService := ""
for _, service := range services.Services {
if service.ServiceAPIVersion == "v2.0" {
foundService = true
fs.ConfigFileSet(name, configResourceURL, service.ServiceResourceID)
oauthBusinessResource = oauth2.SetAuthURLParam("resource", service.ServiceResourceID)
foundService = service.ServiceResourceID
fs.ConfigFileSet(name, configResourceURL, foundService)
oauthBusinessResource = oauth2.SetAuthURLParam("resource", foundService)
fs.Logf(nil, "Found API %s endpoint %s", service.ServiceAPIVersion, service.ServiceEndpointURI)
break
}
// we only support 2.0 API
fs.Logf(nil, "Skipping API %s endpoint %s", service.ServiceAPIVersion, service.ServiceEndpointURI)
fs.Infof(nil, "Skipping API %s endpoint %s", service.ServiceAPIVersion, service.ServiceEndpointURI)
}
if !foundService {
log.Fatalf("No Service found")
if foundService == "" {
fs.Errorf(nil, "No Service found")
return
}
fs.ConfigFileDeleteKey(name, fs.ConfigToken)
err = oauthutil.Config("onedrivebusiness", name, oauthBusinessConfig, oauthBusinessResource)
// get the token from the inital config
// we need to update the token with a resource
// specific token we will query now
token, err := oauthutil.GetToken(name)
if err != nil {
log.Fatalf("Failed to configure token: %v", err)
fs.Errorf(nil, "Error while getting token: %s", err)
return
}
// values for the token query
values := url.Values{}
values.Set("refresh_token", token.RefreshToken)
values.Set("grant_type", "refresh_token")
values.Set("resource", foundService)
values.Set("client_id", oauthBusinessConfig.ClientID)
values.Set("client_secret", oauthBusinessConfig.ClientSecret)
opts = rest.Opts{
Method: "POST",
RootURL: oauthBusinessConfig.Endpoint.TokenURL,
ContentType: "application/x-www-form-urlencoded",
Body: strings.NewReader(values.Encode()),
}
// tokenJSON is the struct representing the HTTP response from OAuth2
// providers returning a token in JSON form.
// we are only interested in the new tokens, all other fields we don't care
type tokenJSON struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
jsonToken := tokenJSON{}
resp, err = srv.CallJSON(&opts, nil, &jsonToken)
if err != nil {
fs.Errorf(nil, "Failed to get resource token: %v", err)
return
}
if resp.StatusCode != 200 {
fs.Errorf(nil, "Failed to get resource token: Got HTTP error code %d", resp.StatusCode)
return
}
// update the tokens
token.AccessToken = jsonToken.AccessToken
token.RefreshToken = jsonToken.RefreshToken
// finally save them in the config
err = oauthutil.PutToken(name, token, true)
if err != nil {
fs.Errorf(nil, "Error while setting token: %s", err)
}
}
},