mirror of
https://github.com/rclone/rclone.git
synced 2025-12-06 00:03:32 +00:00
Compare commits
3 Commits
copilot/fi
...
jotta-auth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f838c2a2f2 | ||
|
|
49103c7348 | ||
|
|
697874e399 |
@@ -17,7 +17,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -60,7 +60,7 @@ const (
|
||||
configVersion = 1
|
||||
|
||||
defaultTokenURL = "https://id.jottacloud.com/auth/realms/jottacloud/protocol/openid-connect/token"
|
||||
defaultClientID = "jottacli"
|
||||
defaultClientID = "jottacli" // Identified as "Jottacloud CLI" in "My logged in devices"
|
||||
|
||||
legacyTokenURL = "https://api.jottacloud.com/auth/v1/token"
|
||||
legacyRegisterURL = "https://api.jottacloud.com/auth/v1/register"
|
||||
@@ -69,27 +69,29 @@ const (
|
||||
legacyConfigVersion = 0
|
||||
)
|
||||
|
||||
func getWhitelabelServices() map[string]struct {
|
||||
name, domain, realm, clientID string
|
||||
scopes []string
|
||||
} {
|
||||
return map[string]struct {
|
||||
name string
|
||||
domain string
|
||||
realm string
|
||||
clientID string
|
||||
scopes []string
|
||||
}{
|
||||
"telia_se": {"Telia Cloud (Sweden)", "cloud-auth.telia.se", "telia_se", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"telia_no": {"Telia Sky (Norway)", "sky-auth.telia.no", "get", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"tele2": {"Tele2 Cloud (Sweden)", "mittcloud-auth.tele2.se", "comhem", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"onlime": {"Onlime (Denmark)", "cloud-auth.onlime.dk", "onlime_wl", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"elkjop": {"Elkjøp Cloud (Norway)", "cloud.elkjop.no", "elkjop", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"elgiganten_se": {"Elgiganten Cloud (Sweden)", "cloud.elgiganten.se", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"elgiganten_dk": {"Elgiganten Cloud (Denmark)", "cloud.elgiganten.dk", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"gigantti": {"Gigantti Cloud (Finland)", "cloud.gigantti.fi", "gigantti", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"elko": {"ELKO Cloud (Iceland)", "cloud.elko.is", "elko", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
"letsgo": {"Let's Go Cloud (Germany)", "letsgo.jotta.cloud", "letsgo", "desktop-win", []string{"openid", "offline_access"}},
|
||||
type service struct {
|
||||
key string
|
||||
name string
|
||||
domain string
|
||||
realm string
|
||||
clientID string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
func getServices() []service {
|
||||
return []service{
|
||||
{"jottacloud", "Jottacloud", "id.jottacloud.com", "jottacloud", "desktop", []string{"openid", "jotta-default", "offline_access"}}, // Chose client id "desktop" here, will be identified as "Jottacloud for Desktop" in "My logged in devices", but could have used "jottacli" here as well.
|
||||
{"elkjop", "Elkjøp Cloud (Norway)", "cloud.elkjop.no", "elkjop", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"elgiganten_dk", "Elgiganten Cloud (Denmark)", "cloud.elgiganten.dk", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"elgiganten_se", "Elgiganten Cloud (Sweden)", "cloud.elgiganten.se", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"elko", "ELKO Cloud (Iceland)", "cloud.elko.is", "elko", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"gigantti", "Gigantti Cloud (Finland)", "cloud.gigantti.fi", "gigantti", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"telia_se", "Telia Cloud (Sweden)", "cloud-auth.telia.se", "telia_se", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"telia_no", "Telia Sky (Norway)", "sky-auth.telia.no", "get", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"tele2", "Tele2 Cloud (Sweden)", "mittcloud-auth.tele2.se", "comhem", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"onlime", "Onlime (Denmark)", "cloud-auth.onlime.dk", "onlime_wl", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"mediamarkt", "MediaMarkt Cloud", "mediamarkt.jottacloud.com", "mediamarkt", "desktop", []string{"openid", "jotta-default", "offline_access"}},
|
||||
{"letsgo", "Let's Go Cloud (Germany)", "letsgo.jotta.cloud", "letsgo", "desktop-win", []string{"openid", "offline_access"}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,20 +178,32 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
|
||||
}
|
||||
return fs.ConfigChooseExclusiveFixed("auth_type_done", "config_type", `Type of authentication.`, []fs.OptionExample{{
|
||||
Value: "standard",
|
||||
Help: "Standard authentication.\nUse this if you're a normal Jottacloud user.",
|
||||
Help: `Standard authentication.
|
||||
This is primarily supported by the official service, but may also be supported
|
||||
by some of the white-label services. It is designed for command-line
|
||||
applications, and you will be asked to enter a single-use personal login token
|
||||
which you must manually generate from the account security settings in the
|
||||
web interface of your service.`,
|
||||
}, {
|
||||
Value: "whitelabel",
|
||||
Help: "Whitelabel authentication.\nUse this if you are using the service offered by a third party such as Telia, Tele2, Onlime, Elkjøp, etc.",
|
||||
Value: "traditional",
|
||||
Help: `Traditional authentication.
|
||||
This is supported by the official service and most of the white-label
|
||||
services, you will be asked which service to connect to. You need to be on
|
||||
a machine with an internet-connected web browser.`,
|
||||
}, {
|
||||
Value: "legacy",
|
||||
Help: "Legacy authentication.\nThis is no longer supported by any known services and not recommended for normal users.",
|
||||
Help: `Legacy authentication.
|
||||
This is no longer supported by any known services and not recommended used.
|
||||
You will be asked for your account's username and password.`,
|
||||
}})
|
||||
case "auth_type_done":
|
||||
// Jump to next state according to config chosen
|
||||
return fs.ConfigGoto(conf.Result)
|
||||
case "standard": // configure a jottacloud backend using the modern JottaCli token based authentication
|
||||
m.Set("configVersion", fmt.Sprint(configVersion))
|
||||
return fs.ConfigInput("standard_token", "config_login_token", "Personal login token.\nGenerate here: https://www.jottacloud.com/web/secure")
|
||||
return fs.ConfigInput("standard_token", "config_login_token", `Personal login token.
|
||||
Generate it from the account security settings in the web interface of your
|
||||
service, for the official service on https://www.jottacloud.com/web/secure.`)
|
||||
case "standard_token":
|
||||
loginToken := conf.Result
|
||||
m.Set(configClientID, defaultClientID)
|
||||
@@ -206,29 +220,28 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
|
||||
return nil, fmt.Errorf("error while saving token: %w", err)
|
||||
}
|
||||
return fs.ConfigGoto("choose_device")
|
||||
case "whitelabel":
|
||||
whitelabels := getWhitelabelServices()
|
||||
options := make([]fs.OptionExample, 0, len(whitelabels))
|
||||
for key, val := range whitelabels {
|
||||
case "traditional":
|
||||
services := getServices()
|
||||
options := make([]fs.OptionExample, 0, len(services))
|
||||
for _, service := range services {
|
||||
options = append(options, fs.OptionExample{
|
||||
Value: key,
|
||||
Help: val.name,
|
||||
Value: service.key,
|
||||
Help: service.name,
|
||||
})
|
||||
}
|
||||
sort.Slice(options, func(i, j int) bool {
|
||||
return options[i].Help < options[j].Help
|
||||
})
|
||||
return fs.ConfigChooseExclusiveFixed("whitelabel_type", "config_whitelabel",
|
||||
return fs.ConfigChooseExclusiveFixed("traditional_type", "config_traditional",
|
||||
"White-label service. This decides the domain name to connect to and\nthe authentication configuration to use.",
|
||||
options)
|
||||
case "whitelabel_type":
|
||||
whitelabel, ok := getWhitelabelServices()[conf.Result]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected whitelabel %q", conf.Result)
|
||||
case "traditional_type":
|
||||
services := getServices()
|
||||
i := slices.IndexFunc(services, func(s service) bool { return s.key == conf.Result })
|
||||
if i == -1 {
|
||||
return nil, fmt.Errorf("unexpected service %q", conf.Result)
|
||||
}
|
||||
service := services[i]
|
||||
opts := rest.Opts{
|
||||
Method: "GET",
|
||||
RootURL: "https://" + whitelabel.domain + "/auth/realms/" + whitelabel.realm + "/.well-known/openid-configuration",
|
||||
RootURL: "https://" + service.domain + "/auth/realms/" + service.realm + "/.well-known/openid-configuration",
|
||||
}
|
||||
var wellKnown api.WellKnown
|
||||
srv := rest.NewClient(fshttp.NewClient(ctx))
|
||||
@@ -237,14 +250,14 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
|
||||
return nil, fmt.Errorf("failed to get authentication provider configuration: %w", err)
|
||||
}
|
||||
m.Set("configVersion", fmt.Sprint(configVersion))
|
||||
m.Set(configClientID, whitelabel.clientID)
|
||||
m.Set(configClientID, service.clientID)
|
||||
m.Set(configTokenURL, wellKnown.TokenEndpoint)
|
||||
return oauthutil.ConfigOut("choose_device", &oauthutil.Options{
|
||||
OAuth2Config: &oauthutil.Config{
|
||||
AuthURL: wellKnown.AuthorizationEndpoint,
|
||||
TokenURL: wellKnown.TokenEndpoint,
|
||||
ClientID: whitelabel.clientID,
|
||||
Scopes: whitelabel.scopes,
|
||||
ClientID: service.clientID,
|
||||
Scopes: service.scopes,
|
||||
RedirectURL: oauthutil.RedirectLocalhostURL,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -28,60 +28,86 @@ as described [below](#whitelabel-authentication):
|
||||
- Onlime
|
||||
- Onlime (onlime.dk)
|
||||
- MediaMarkt
|
||||
- MediaMarkt Cloud (mediamarkt.jottacloud.com)
|
||||
- Let's Go Cloud (letsgo.jotta.cloud)
|
||||
|
||||
Paths are specified as `remote:path`
|
||||
|
||||
Paths may be as deep as required, e.g. `remote:directory/subdirectory`.
|
||||
|
||||
## Authentication types
|
||||
## Authentication
|
||||
|
||||
Some of the white-label versions uses a different authentication method than the
|
||||
official service, and you have to choose the correct one when setting up the remote.
|
||||
|
||||
### Standard authentication
|
||||
|
||||
The standard authentication method used by the official service (jottacloud.com),
|
||||
as well as some of the white-label services, is based on OAuth 2.0 and OpenID
|
||||
Connect (OIDC), and requires you to generate a single-use personal login token
|
||||
from the account security settings in the service's web interface. Log in to your
|
||||
account, go to "Settings" and then "Security", or use the direct link presented
|
||||
to you by rclone when configuring the remote:
|
||||
<https://www.jottacloud.com/web/secure>. Scroll down to the section "Personal login
|
||||
token", and click the "Generate" button. Note that if you are using a white-label
|
||||
service you probably can't use the direct link, you need to find the same page in
|
||||
their dedicated web interface, and also it may be in a different location than
|
||||
described above.
|
||||
Authentication in Jottacloud is in general based on OAuth 2.0 and OpenID
|
||||
Connect (OIDC). There are different variants to choose from, described below.
|
||||
Some of the variants are only supported by the official service and not
|
||||
white-label services, so this must be taken into consideration when choosing.
|
||||
|
||||
To access your account from multiple instances of rclone, you need to configure
|
||||
each of them with a separate personal login token. E.g. you create a Jottacloud
|
||||
remote with rclone in one location, and copy the configuration file to a second
|
||||
location where you also want to run rclone and access the same remote. Then you
|
||||
need to replace the token for one of them, using the [config reconnect](https://rclone.org/commands/rclone_config_reconnect/)
|
||||
command, which requires you to generate a new personal login token and supply
|
||||
as input. If you do not do this, the token may easily end up being invalidated,
|
||||
resulting in both instances failing with an error message something along the
|
||||
lines of:
|
||||
each of them separately. E.g. you create a Jottacloud remote with rclone in one
|
||||
location, and copy the configuration file to a second location where you also
|
||||
want to run rclone and access the same remote. Then you need to replace the
|
||||
token for one of them, using the [config reconnect](https://rclone.org/commands/rclone_config_reconnect/)
|
||||
command. For standard authentication (described below) this means you will have
|
||||
to generate a new personal login token and supply as input. If you do not do
|
||||
this, the token may easily end up being invalidated, resulting in both
|
||||
instances failing with an error message something along the lines of:
|
||||
|
||||
```text
|
||||
oauth2: cannot fetch token: 400 Bad Request
|
||||
Response: {"error":"invalid_grant","error_description":"Stale token"}
|
||||
```
|
||||
|
||||
When this happens, you need to replace the token as described above to be able
|
||||
to use your remote again.
|
||||
The background for this is that OAuth tokens from Jottacloud normally have one
|
||||
hour expiry, after which they will be automatically refreshed by rclone.
|
||||
Jottacloud will then refresh not only the access token, but also the refresh
|
||||
token. Any requests using a previous refresh token will be flagged, and lead
|
||||
to the stale token error. When this happens, you need to replace the token as
|
||||
described above to be able to use your remote again.
|
||||
|
||||
All personal login tokens you have taken into use will be listed in the web
|
||||
interface under "My logged in devices", and from the right side of that list
|
||||
you can click the "X" button to revoke individual tokens.
|
||||
Each time you are granted access with a new token, it will listed in the web
|
||||
interface under "My logged in devices". From the right side of that list you
|
||||
can click the "X" button to revoke access. This will effectively disable the
|
||||
refresh token, which means you will still have access using an existing access
|
||||
token until that expires, but you will not be able to refresh it.
|
||||
|
||||
### Whitelabel authentication
|
||||
### Standard
|
||||
|
||||
Most of the white-label versions uses a slightly different authentication flow,
|
||||
where it doesn't offer the option of creating a CLI token, and the username
|
||||
is generated internally. To setup rclone to use one of these, choose white-label
|
||||
authentication in the setup process, and then select the specific service
|
||||
in the next step.
|
||||
This is an OAuth variant designed for command-line applications. It is
|
||||
primarily supported by the official service (jottacloud.com), but may also be
|
||||
supported by some of the white-label services. The specific domain name and
|
||||
endpoint to connect to are found automatically (it is encoded into the supplied
|
||||
login token, described next).
|
||||
|
||||
When configuring a remote, you are asked to enter a single-use personal login
|
||||
token, which you must manually generate from the account security settings in
|
||||
the service's web interface. You do not need a web browser on the same machine
|
||||
like with traditional OAuth, but need to use a web browser somewhere, and be
|
||||
able to be copy the generated string into your rclone configuration session.
|
||||
|
||||
Log in to your account, go to "Settings" and then "Security", or use the direct
|
||||
link presented to you by rclone when configuring the remote:
|
||||
<https://www.jottacloud.com/web/secure>. Scroll down to the section "Personal
|
||||
login token", and click the "Generate" button. Note that if you are using a
|
||||
white-label service you probably can't use the direct link, you need to find
|
||||
the same page in their dedicated web interface, and also it may be in a
|
||||
different location than described above.
|
||||
|
||||
When you have successfully authenticated using a personal login token, which
|
||||
means you have received a proper OAuth token, there will be an entry in the
|
||||
"My logged in devices" list in the web interface. It will be listed with
|
||||
application name "Jottacloud CLI".
|
||||
|
||||
### Traditional
|
||||
|
||||
Jottacloud also supports a more traditional OAuth variant. Most of the
|
||||
white-label services supports this, and often only this as they do not support
|
||||
personal login tokens. This method relies on pre-defined domain names and
|
||||
endpoints, and rclone must therefore explicitly add any white-label services
|
||||
that should be supported.
|
||||
|
||||
When configuring a remote, you must interactively login to an OAuth
|
||||
authorization web site, and a one-time authorization code are automatically
|
||||
sent back to rclone, which it uses to request a token.
|
||||
|
||||
Note that when setting this up, you need to be on a machine with an
|
||||
internet-connected web browser. If you need it on a machine where this is not
|
||||
@@ -90,14 +116,18 @@ and copy it from there. The jottacloud backend does not support the
|
||||
`rclone authorize` command. See the [remote setup docs](/remote_setup) for
|
||||
details.
|
||||
|
||||
### Legacy authentication
|
||||
When you have successfully authenticated, there will be an entry in the
|
||||
"My logged in devices" list in the web interface. It will typically be listed
|
||||
with application name "Jottacloud for Desktop" or similar (it depends on the
|
||||
white-label service configuration).
|
||||
|
||||
Originally Jottacloud used an older authentication method, not based on OpenID
|
||||
Connect, which required the username and password to be specified. Since
|
||||
Jottacloud migrated to the newer method, handled by the standard authentication,
|
||||
some white-label versions (those from Elkjøp) still used the legacy method for
|
||||
a long time. Currently there are no known uses of this, it is still supported
|
||||
by rclone, but the support will be removed in a future version.
|
||||
### Legacy
|
||||
|
||||
Originally Jottacloud used an OAuth variant which required your account's
|
||||
username and password to be specified. When Jottacloud migrated to the newer
|
||||
methods, some white-label versions (those from Elkjøp) still used this legacy
|
||||
method for a long time. Currently there are no known uses of this, it is still
|
||||
supported by rclone, but the support will be removed in a future version.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -151,19 +181,27 @@ Type of authentication.
|
||||
Choose a number from below, or type in an existing value of type string.
|
||||
Press Enter for the default (standard).
|
||||
/ Standard authentication.
|
||||
1 | Use this if you're a normal Jottacloud user.
|
||||
| This is primarily supported by the official service, but may also be supported
|
||||
| by some of the white-label services. It is designed for command-line
|
||||
1 | applications, and you will be asked to enter a single-use personal login token
|
||||
| which you must manually generate from the account security settings in the
|
||||
| web interface of your service.
|
||||
\ (standard)
|
||||
/ Whitelabel authentication.
|
||||
2 | Use this if you are using the service offered by a third party such as Telia, Tele2, Onlime, Elkjøp, etc.
|
||||
\ (whitelabel)
|
||||
/ Traditional authentication.
|
||||
| This is supported by the official service and most of the white-label
|
||||
2 | services, you will be asked which service to connect to. You need to be on
|
||||
| a machine with an internet-connected web browser.
|
||||
\ (traditional)
|
||||
/ Legacy authentication.
|
||||
3 | This is no longer supported by any known services and not recommended for normal users.
|
||||
3 | This is no longer supported by any known services and not recommended used.
|
||||
| You will be asked for your account's username and password.
|
||||
\ (legacy)
|
||||
config_type> 1
|
||||
|
||||
Option config_login_token.
|
||||
Personal login token.
|
||||
Generate here: https://www.jottacloud.com/web/secure
|
||||
Generate it from the account security settings in the web interface of your
|
||||
service, for the official service on https://www.jottacloud.com/web/secure.
|
||||
Enter a value.
|
||||
config_login_token> <your token here>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user