jottacloud: add support whitelabel versions

This commit is contained in:
buengese 2019-12-28 17:45:04 +01:00 committed by buengese
parent 584e705c0c
commit 8a2d1dbe24
2 changed files with 59 additions and 14 deletions

View file

@ -54,6 +54,37 @@ type LoginToken struct {
AuthToken string `json:"auth_token"` AuthToken string `json:"auth_token"`
} }
// WellKnown contains some configuration parameters for setting up endpoints
type WellKnown struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
TokenIntrospectionEndpoint string `json:"token_introspection_endpoint"`
UserinfoEndpoint string `json:"userinfo_endpoint"`
EndSessionEndpoint string `json:"end_session_endpoint"`
JwksURI string `json:"jwks_uri"`
CheckSessionIframe string `json:"check_session_iframe"`
GrantTypesSupported []string `json:"grant_types_supported"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported"`
RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported"`
ResponseNodesSupported []string `json:"response_modes_supported"`
RegistrationEndpoint string `json:"registration_endpoint"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported"`
ClaimsSupported []string `json:"claims_supported"`
ClaimTypesSupported []string `json:"claim_types_supported"`
ClaimsParameterSupported bool `json:"claims_parameter_supported"`
ScopesSupported []string `json:"scopes_supported"`
RequestParameterSupported bool `json:"request_parameter_supported"`
RequestURIParameterSupported bool `json:"request_uri_parameter_supported"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
TLSClientCertificateBoundAccessTokens bool `json:"tls_client_certificate_bound_access_tokens"`
IntrospectionEndpoint string `json:"introspection_endpoint"`
}
// TokenJSON is the struct representing the HTTP response from OAuth2 // TokenJSON is the struct representing the HTTP response from OAuth2
// providers returning a token in JSON form. // providers returning a token in JSON form.
type TokenJSON struct { type TokenJSON struct {

View file

@ -49,10 +49,11 @@ const (
rootURL = "https://www.jottacloud.com/jfs/" rootURL = "https://www.jottacloud.com/jfs/"
apiURL = "https://api.jottacloud.com/" apiURL = "https://api.jottacloud.com/"
baseURL = "https://www.jottacloud.com/" baseURL = "https://www.jottacloud.com/"
tokenURL = "https://id.jottacloud.com/auth/realms/jottacloud/protocol/openid-connect/token" defaultTokenURL = "https://id.jottacloud.com/auth/realms/jottacloud/protocol/openid-connect/token"
cachePrefix = "rclone-jcmd5-" cachePrefix = "rclone-jcmd5-"
configDevice = "device" configDevice = "device"
configMountpoint = "mountpoint" configMountpoint = "mountpoint"
configTokenURL = "tokenURL"
configVersion = 1 configVersion = 1
) )
@ -61,8 +62,8 @@ var (
oauthConfig = &oauth2.Config{ oauthConfig = &oauth2.Config{
ClientID: "jottacli", ClientID: "jottacli",
Endpoint: oauth2.Endpoint{ Endpoint: oauth2.Endpoint{
AuthURL: tokenURL, AuthURL: defaultTokenURL,
TokenURL: tokenURL, TokenURL: defaultTokenURL,
}, },
RedirectURL: oauthutil.RedirectLocalhostURL, RedirectURL: oauthutil.RedirectLocalhostURL,
} }
@ -85,8 +86,6 @@ func init() {
log.Fatalf("Failed to parse config version - corrupted config") log.Fatalf("Failed to parse config version - corrupted config")
} }
refresh = ver != configVersion refresh = ver != configVersion
} else {
refresh = true
} }
if refresh { if refresh {
@ -109,7 +108,7 @@ func init() {
fmt.Printf("Login Token> ") fmt.Printf("Login Token> ")
loginToken := config.ReadLine() loginToken := config.ReadLine()
token, err := doAuth(ctx, srv, loginToken) token, err := doAuth(ctx, srv, loginToken, m)
if err != nil { if err != nil {
log.Fatalf("Failed to get oauth token: %s", err) log.Fatalf("Failed to get oauth token: %s", err)
} }
@ -244,12 +243,13 @@ func shouldRetry(resp *http.Response, err error) (bool, error) {
} }
// doAuth runs the actual token request // doAuth runs the actual token request
func doAuth(ctx context.Context, srv *rest.Client, loginTokenBase64 string) (token oauth2.Token, err error) { func doAuth(ctx context.Context, srv *rest.Client, loginTokenBase64 string, m configmap.Mapper) (token oauth2.Token, err error) {
loginTokenBytes, err := base64.StdEncoding.DecodeString(loginTokenBase64) loginTokenBytes, err := base64.StdEncoding.DecodeString(loginTokenBase64)
if err != nil { if err != nil {
return token, err return token, err
} }
// decode login token
var loginToken api.LoginToken var loginToken api.LoginToken
decoder := json.NewDecoder(bytes.NewReader(loginTokenBytes)) decoder := json.NewDecoder(bytes.NewReader(loginTokenBytes))
err = decoder.Decode(&loginToken) err = decoder.Decode(&loginToken)
@ -257,17 +257,22 @@ func doAuth(ctx context.Context, srv *rest.Client, loginTokenBase64 string) (tok
return token, err return token, err
} }
// we don't seem to need any data from this link but the API is not happy if skip it // retrieve endpoint urls
opts := rest.Opts{ opts := rest.Opts{
Method: "GET", Method: "GET",
RootURL: loginToken.WellKnownLink, RootURL: loginToken.WellKnownLink,
NoResponse: true,
} }
_, err = srv.Call(ctx, &opts) var wellKnown api.WellKnown
_, err = srv.CallJSON(ctx, &opts, nil, &wellKnown)
if err != nil { if err != nil {
return token, err return token, err
} }
// save the tokenurl
oauthConfig.Endpoint.AuthURL = wellKnown.TokenEndpoint
oauthConfig.Endpoint.TokenURL = wellKnown.TokenEndpoint
m.Set(configTokenURL, wellKnown.TokenEndpoint)
// prepare out token request with username and password // prepare out token request with username and password
values := url.Values{} values := url.Values{}
values.Set("client_id", "jottacli") values.Set("client_id", "jottacli")
@ -459,6 +464,7 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
return nil, err return nil, err
} }
// Check config version
var ok bool var ok bool
var version string var version string
if version, ok = m.Get("configVersion"); ok { if version, ok = m.Get("configVersion"); ok {
@ -472,15 +478,23 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
return nil, errors.New("Outdated config - please reconfigure this backend") return nil, errors.New("Outdated config - please reconfigure this backend")
} }
rootIsDir := strings.HasSuffix(root, "/") // if custome endpoints are set use them else stick with defaults
root = parsePath(root) if tokenURL, ok := m.Get(configTokenURL); ok {
oauthConfig.Endpoint.TokenURL = tokenURL
// jottacloud is weird. we need to use the tokenURL as authURL
oauthConfig.Endpoint.AuthURL = tokenURL
}
// Create OAuth Client
baseClient := fshttp.NewClient(fs.Config) baseClient := fshttp.NewClient(fs.Config)
oAuthClient, ts, err := oauthutil.NewClientWithBaseClient(name, m, oauthConfig, baseClient) oAuthClient, ts, err := oauthutil.NewClientWithBaseClient(name, m, oauthConfig, baseClient)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed to configure Jottacloud oauth client") return nil, errors.Wrap(err, "Failed to configure Jottacloud oauth client")
} }
rootIsDir := strings.HasSuffix(root, "/")
root = parsePath(root)
f := &Fs{ f := &Fs{
name: name, name: name,
root: root, root: root,