-
Notifications
You must be signed in to change notification settings - Fork 127
[APP-14483] Parse API key from config and use it to authenticate to app #5558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
33e4e9c
bc042ef
3267705
82ed963
2940949
8cfcb44
4340381
b5a0019
0325ba3
1555c12
7b2ef97
001db6b
e413527
c7aa225
ee1ca55
325a984
a586003
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -562,6 +562,7 @@ type Cloud struct { | |
| Secret string | ||
| LocationSecret string // Deprecated: Use LocationSecrets | ||
| LocationSecrets []LocationSecret | ||
| APIKey APIKey | ||
| LocationID string | ||
| PrimaryOrgID string | ||
| MachineID string | ||
|
|
@@ -589,6 +590,7 @@ type cloudData struct { | |
|
|
||
| LocationSecret string `json:"location_secret"` | ||
| LocationSecrets []LocationSecret `json:"location_secrets"` | ||
| APIKey APIKey `json:"api_key"` | ||
| LocationID string `json:"location_id"` | ||
| PrimaryOrgID string `json:"primary_org_id"` | ||
| MachineID string `json:"machine_id"` | ||
|
|
@@ -606,6 +608,33 @@ type cloudData struct { | |
| TLSPrivateKey string `json:"tls_private_key"` | ||
| } | ||
|
|
||
| // APIKey is the cloud app authentication credential | ||
| type APIKey struct { | ||
| ID string `json:"id"` | ||
| Key string `json:"value"` | ||
| } | ||
|
|
||
| // IsFullySet returns true if an APIKey has both the ID and Key fields set. | ||
| func (a APIKey) IsFullySet() bool { | ||
| return a.ID != "" && a.Key != "" | ||
| } | ||
|
|
||
| // IsPartiallySet returns true if only one of the ID or Key fields are set. | ||
| func (a APIKey) IsPartiallySet() bool { | ||
| return (a.ID == "" && a.Key != "") || (a.ID != "" && a.Key == "") | ||
| } | ||
|
|
||
| // GetCloudCredsDialOpt returns a dial option with the cloud credentials for this cloud config. | ||
| // API keys are always preferred over robot secrets. If neither are set, nil is returned. | ||
| func (config *Cloud) GetCloudCredsDialOpt() rpc.DialOption { | ||
| if config.APIKey.IsFullySet() { | ||
| return rpc.WithEntityCredentials(config.APIKey.ID, rpc.Credentials{rutils.CredentialsTypeAPIKey, config.APIKey.Key}) | ||
| } else if config.Secret != "" { | ||
| return rpc.WithEntityCredentials(config.ID, rpc.Credentials{rutils.CredentialsTypeRobotSecret, config.Secret}) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // UnmarshalJSON unmarshals JSON data into this config. | ||
| func (config *Cloud) UnmarshalJSON(data []byte) error { | ||
| var temp cloudData | ||
|
|
@@ -617,6 +646,7 @@ func (config *Cloud) UnmarshalJSON(data []byte) error { | |
| Secret: temp.Secret, | ||
| LocationSecret: temp.LocationSecret, | ||
| LocationSecrets: temp.LocationSecrets, | ||
| APIKey: temp.APIKey, | ||
| LocationID: temp.LocationID, | ||
| PrimaryOrgID: temp.PrimaryOrgID, | ||
| MachineID: temp.MachineID, | ||
|
|
@@ -648,6 +678,7 @@ func (config Cloud) MarshalJSON() ([]byte, error) { | |
| Secret: config.Secret, | ||
| LocationSecret: config.LocationSecret, | ||
| LocationSecrets: config.LocationSecrets, | ||
| APIKey: config.APIKey, | ||
| LocationID: config.LocationID, | ||
| PrimaryOrgID: config.PrimaryOrgID, | ||
| MachineID: config.MachineID, | ||
|
|
@@ -680,8 +711,10 @@ func (config *Cloud) Validate(path string, fromCloud bool) error { | |
| if config.LocalFQDN == "" { | ||
| return resource.NewConfigValidationFieldRequiredError(path, "local_fqdn") | ||
| } | ||
| } else if config.Secret == "" { | ||
| return resource.NewConfigValidationFieldRequiredError(path, "secret") | ||
| } else if config.APIKey.IsPartiallySet() { | ||
| return resource.NewConfigValidationFieldRequiredError(path, "api_key") | ||
| } else if config.Secret == "" && !config.APIKey.IsFullySet() { | ||
| return resource.NewConfigValidationFieldRequiredError(path, "api_key") | ||
| } | ||
| if config.RefreshInterval == 0 { | ||
| config.RefreshInterval = 10 * time.Second | ||
|
|
@@ -1067,6 +1100,7 @@ func CreateTLSWithCert(cfg *Config) (*tls.Config, error) { | |
| func ProcessConfig(in *Config) (*Config, error) { | ||
| out := *in | ||
| var selfCreds *rpc.Credentials | ||
| var selfAuthEntity string | ||
| if in.Cloud != nil { | ||
| // We expect a cloud config from app to always contain a non-empty `TLSCertificate` field. | ||
| // We do this empty string check just to cope with unexpected input, such as cached configs | ||
|
|
@@ -1078,7 +1112,13 @@ func ProcessConfig(in *Config) (*Config, error) { | |
| } | ||
| out.Network.TLSConfig = tlsConfig | ||
| } | ||
| selfCreds = &rpc.Credentials{rutils.CredentialsTypeRobotSecret, in.Cloud.Secret} | ||
| if in.Cloud.APIKey.IsFullySet() { | ||
| selfCreds = &rpc.Credentials{rutils.CredentialsTypeAPIKey, in.Cloud.APIKey.Key} | ||
| selfAuthEntity = in.Cloud.APIKey.ID | ||
| } else { | ||
| selfCreds = &rpc.Credentials{rutils.CredentialsTypeRobotSecret, in.Cloud.Secret} | ||
| selfAuthEntity = in.Cloud.ID | ||
| } | ||
| } | ||
|
|
||
| out.Remotes = make([]Remote, len(in.Remotes)) | ||
|
|
@@ -1093,7 +1133,7 @@ func ProcessConfig(in *Config) (*Config, error) { | |
| } | ||
| remoteCopy.Auth.Managed = true | ||
| remoteCopy.Auth.SignalingServerAddress = in.Cloud.SignalingAddress | ||
| remoteCopy.Auth.SignalingAuthEntity = in.Cloud.ID | ||
| remoteCopy.Auth.SignalingAuthEntity = selfAuthEntity | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this used for?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's used to authenticate to the signaling server for creating a WebRTC connection to a remote robot I believe |
||
| remoteCopy.Auth.SignalingCreds = selfCreds | ||
| } | ||
| out.Remotes[idx] = remoteCopy | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -145,6 +145,9 @@ func prettyDiff(left, right Config) (string, error) { | |
| conf.Cloud.LocationSecrets[i].Secret = mask | ||
| } | ||
| } | ||
| if conf.Cloud.APIKey.Key != "" { | ||
| conf.Cloud.APIKey.Key = mask | ||
| } | ||
|
Comment on lines
+148
to
+150
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why just compare key and not id?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // Not really a secret but annoying to diff | ||
| if conf.Cloud.TLSCertificate != "" { | ||
| conf.Cloud.TLSCertificate = mask | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this changed after but would be great to match the struct name with the json value -> key <> value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah good catch I overlooked this thanks!