Skip to content

Commit 00ab385

Browse files
authored
Merge pull request #234 from wongle/akamai-plugin
New plugin: Akamai CLI
2 parents 65ba5f7 + bfd12cb commit 00ab385

File tree

8 files changed

+317
-16
lines changed

8 files changed

+317
-16
lines changed

plugins/akamai/akamai.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package akamai
2+
3+
import (
4+
"github.com/1Password/shell-plugins/sdk"
5+
"github.com/1Password/shell-plugins/sdk/needsauth"
6+
"github.com/1Password/shell-plugins/sdk/schema"
7+
"github.com/1Password/shell-plugins/sdk/schema/credname"
8+
)
9+
10+
func AkamaiCLI() schema.Executable {
11+
return schema.Executable{
12+
Name: "Akamai CLI",
13+
Runs: []string{"akamai"},
14+
DocsURL: sdk.URL("https://techdocs.akamai.com/developer/docs/about-clis"),
15+
NeedsAuth: needsauth.IfAll(
16+
needsauth.NotForHelpOrVersion(),
17+
needsauth.NotWithoutArgs(),
18+
needsauth.NotWhenContainsArgs("config"), // skip 1Password authentication for "akamai config" and its subcommands
19+
needsauth.NotWhenContainsArgs("install"), // skip 1Password authentication for "akamai install" and its subcommands
20+
needsauth.NotWhenContainsArgs("get"), // skip 1Password authentication for "akamai get" and its subcommands
21+
needsauth.NotWhenContainsArgs("list"), // skip 1Password authentication for "akamai list" and its subcommands
22+
needsauth.NotWhenContainsArgs("search"), // skip 1Password authentication for "akamai search" and its subcommands
23+
needsauth.NotWhenContainsArgs("uninstall"), // skip 1Password authentication for "akamai uninstall" and its subcommands
24+
needsauth.NotWhenContainsArgs("update"), // skip 1Password authentication for "akamai update" and its subcommands
25+
needsauth.NotWhenContainsArgs("upgrade"), // skip 1Password authentication for "akamai upgrade" and its subcommands
26+
),
27+
Uses: []schema.CredentialUsage{
28+
{
29+
Name: credname.APIClientCredentials,
30+
},
31+
},
32+
}
33+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package akamai
2+
3+
import (
4+
"context"
5+
6+
"github.com/1Password/shell-plugins/sdk"
7+
"github.com/1Password/shell-plugins/sdk/importer"
8+
"github.com/1Password/shell-plugins/sdk/provision"
9+
"github.com/1Password/shell-plugins/sdk/schema"
10+
"github.com/1Password/shell-plugins/sdk/schema/credname"
11+
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
12+
)
13+
14+
func APIClientCredentials() schema.CredentialType {
15+
return schema.CredentialType{
16+
Name: credname.APIClientCredentials,
17+
DocsURL: sdk.URL("https://techdocs.akamai.com/developer/docs/set-up-authentication-credentials"),
18+
ManagementURL: sdk.URL("https://control.akamai.com/apps/identity-management/#/tabs/users/list"),
19+
Fields: []schema.CredentialField{
20+
{
21+
Name: fieldname.ClientSecret,
22+
MarkdownDescription: "Client Secret used to authenticate to Akamai.",
23+
Secret: true,
24+
Composition: &schema.ValueComposition{
25+
Length: 44,
26+
Charset: schema.Charset{
27+
Uppercase: true,
28+
Lowercase: true,
29+
Digits: true,
30+
Symbols: true,
31+
},
32+
},
33+
},
34+
{
35+
Name: fieldname.Host,
36+
MarkdownDescription: "Hostname used to authenticate to Akamai APIs.",
37+
Secret: false,
38+
Composition: &schema.ValueComposition{
39+
Length: 58,
40+
Charset: schema.Charset{
41+
Lowercase: true,
42+
Digits: true,
43+
Specific: []rune{45, 46}, // "-" and "."
44+
},
45+
},
46+
},
47+
{
48+
Name: fieldname.AccessToken,
49+
MarkdownDescription: "Access Token used to authenticate to Akamai.",
50+
Secret: false,
51+
Composition: &schema.ValueComposition{
52+
Length: 38,
53+
Charset: schema.Charset{
54+
Lowercase: true,
55+
Digits: true,
56+
Specific: []rune{45}, // "-"
57+
},
58+
},
59+
},
60+
{
61+
Name: fieldname.ClientToken,
62+
MarkdownDescription: "Client Token used to authenticate to Akamai.",
63+
Secret: false,
64+
Composition: &schema.ValueComposition{
65+
Length: 38,
66+
Charset: schema.Charset{
67+
Lowercase: true,
68+
Digits: true,
69+
Specific: []rune{45}, // "-"
70+
},
71+
},
72+
},
73+
},
74+
DefaultProvisioner: provision.TempFile(configFile,
75+
provision.Filename(".edgerc"),
76+
provision.AddArgs(
77+
"--edgerc", "{{ .Path }}",
78+
"--section", "default",
79+
),
80+
provision.SetPathAsEnvVar("EDGERC"), // for Akamai Terraform provider
81+
),
82+
Importer: importer.TryAll(
83+
TryAkamaiConfigFile(),
84+
)}
85+
}
86+
87+
func configFile(in sdk.ProvisionInput) ([]byte, error) {
88+
contents := "[default]\n"
89+
90+
if clientsecret, ok := in.ItemFields[fieldname.ClientSecret]; ok {
91+
contents += "client_secret = " + clientsecret + "\n"
92+
}
93+
94+
if host, ok := in.ItemFields[fieldname.Host]; ok {
95+
contents += "host = " + host + "\n"
96+
}
97+
98+
if accesstoken, ok := in.ItemFields[fieldname.AccessToken]; ok {
99+
contents += "access_token = " + accesstoken + "\n"
100+
}
101+
102+
if clienttoken, ok := in.ItemFields[fieldname.ClientToken]; ok {
103+
contents += "client_token = " + clienttoken + "\n"
104+
}
105+
106+
return []byte(contents), nil
107+
}
108+
109+
// Load credentials from the ~/.edgerc file.
110+
// Import separate credentials into 1Password based on the sections in the ~/.edgerc file.
111+
func TryAkamaiConfigFile() sdk.Importer {
112+
return importer.TryFile("~/.edgerc", func(ctx context.Context, contents importer.FileContents, in sdk.ImportInput, out *sdk.ImportAttempt) {
113+
configFile, err := contents.ToINI()
114+
if err != nil {
115+
out.AddError(err)
116+
return
117+
}
118+
119+
for _, section := range configFile.Sections() {
120+
profileName := section.Name()
121+
122+
fields := make(map[sdk.FieldName]string)
123+
if section.HasKey("client_secret") && section.Key("client_secret").Value() != "" {
124+
fields[fieldname.ClientSecret] = section.Key("client_secret").Value()
125+
}
126+
if section.HasKey("host") && section.Key("host").Value() != "" {
127+
fields[fieldname.Host] = section.Key("host").Value()
128+
}
129+
if section.HasKey("access_token") && section.Key("access_token").Value() != "" {
130+
fields[fieldname.AccessToken] = section.Key("access_token").Value()
131+
}
132+
if section.HasKey("client_token") && section.Key("client_token").Value() != "" {
133+
fields[fieldname.ClientToken] = section.Key("client_token").Value()
134+
}
135+
136+
// add candidates that contain all required credential fields
137+
if fields[fieldname.ClientSecret] != "" && fields[fieldname.Host] != "" && fields[fieldname.AccessToken] != "" && fields[fieldname.ClientToken] != "" {
138+
out.AddCandidate(sdk.ImportCandidate{
139+
NameHint: importer.SanitizeNameHint(profileName),
140+
Fields: fields,
141+
})
142+
}
143+
}
144+
})
145+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package akamai
2+
3+
import (
4+
"testing"
5+
6+
"github.com/1Password/shell-plugins/sdk"
7+
"github.com/1Password/shell-plugins/sdk/plugintest"
8+
"github.com/1Password/shell-plugins/sdk/schema/fieldname"
9+
)
10+
11+
func TestAPIClientCredentialsProvisioner(t *testing.T) {
12+
plugintest.TestProvisioner(t, APIClientCredentials().DefaultProvisioner, map[string]plugintest.ProvisionCase{
13+
"default": {
14+
ItemFields: map[sdk.FieldName]string{
15+
fieldname.ClientSecret: "abcdE23FNkBxy456z25qx9Yp5CPUxlEfQeTDkfh4QA=I",
16+
fieldname.Host: "akab-lmn789n2k53w7qrs-nfkxaa4lfk3kd6ym.luna.akamaiapis.net",
17+
fieldname.AccessToken: "akab-zyx987xa6osbli4k-e7jf5ikib5jknes3",
18+
fieldname.ClientToken: "akab-nomoflavjuc4422e-fa2xznerxrm3teg7",
19+
},
20+
ExpectedOutput: sdk.ProvisionOutput{
21+
CommandLine: []string{"--edgerc", "/tmp/.edgerc", "--section", "default"},
22+
Files: map[string]sdk.OutputFile{
23+
"/tmp/.edgerc": {Contents: []byte(plugintest.LoadFixture(t, ".edgerc-single"))},
24+
},
25+
Environment: map[string]string{
26+
"EDGERC": "/tmp/.edgerc",
27+
},
28+
},
29+
},
30+
})
31+
}
32+
33+
func TestAPIClientCredentialsImporter(t *testing.T) {
34+
plugintest.TestImporter(t, APIClientCredentials().Importer, map[string]plugintest.ImportCase{
35+
"config file with single credential": {
36+
Files: map[string]string{
37+
"~/.edgerc": plugintest.LoadFixture(t, ".edgerc-single"),
38+
},
39+
ExpectedCandidates: []sdk.ImportCandidate{
40+
{
41+
NameHint: "",
42+
Fields: map[sdk.FieldName]string{
43+
fieldname.ClientSecret: "abcdE23FNkBxy456z25qx9Yp5CPUxlEfQeTDkfh4QA=I",
44+
fieldname.Host: "akab-lmn789n2k53w7qrs-nfkxaa4lfk3kd6ym.luna.akamaiapis.net",
45+
fieldname.AccessToken: "akab-zyx987xa6osbli4k-e7jf5ikib5jknes3",
46+
fieldname.ClientToken: "akab-nomoflavjuc4422e-fa2xznerxrm3teg7",
47+
},
48+
},
49+
},
50+
},
51+
"config file with multiple credentials": {
52+
Files: map[string]string{
53+
"~/.edgerc": plugintest.LoadFixture(t, ".edgerc-multiple"),
54+
},
55+
ExpectedCandidates: []sdk.ImportCandidate{
56+
{
57+
NameHint: "",
58+
Fields: map[sdk.FieldName]string{
59+
fieldname.ClientSecret: "abcdE23FNkBxy456z25qx9Yp5CPUxlEfQeTDkfh4QA=I",
60+
fieldname.Host: "akab-lmn789n2k53w7qrs-nfkxaa4lfk3kd6ym.luna.akamaiapis.net",
61+
fieldname.AccessToken: "akab-zyx987xa6osbli4k-e7jf5ikib5jknes3",
62+
fieldname.ClientToken: "akab-nomoflavjuc4422e-fa2xznerxrm3teg7",
63+
},
64+
},
65+
{
66+
NameHint: "newcredential",
67+
Fields: map[sdk.FieldName]string{
68+
fieldname.ClientSecret: "M9XGZP/D2JedcbABC4Td8XSnHfKKIV4N5n28cj2y6zE=",
69+
fieldname.Host: "akab-ip5n2k53w7nhdcxy-nflxabc432DE1ymd.luna.akamaiapis.net",
70+
fieldname.AccessToken: "akab-abc77fxa6zyxi4k-e7jf5ikib5jknesc3",
71+
fieldname.ClientToken: "akab-moo22awk8765efd-s2yw5zqfrx4jp57cf",
72+
},
73+
},
74+
},
75+
},
76+
})
77+
}

plugins/akamai/plugin.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package akamai
2+
3+
import (
4+
"github.com/1Password/shell-plugins/sdk"
5+
"github.com/1Password/shell-plugins/sdk/schema"
6+
)
7+
8+
func New() schema.Plugin {
9+
return schema.Plugin{
10+
Name: "akamai",
11+
Platform: schema.PlatformInfo{
12+
Name: "Akamai",
13+
Homepage: sdk.URL("https://akamai.com"),
14+
},
15+
Credentials: []schema.CredentialType{
16+
APIClientCredentials(),
17+
},
18+
Executables: []schema.Executable{
19+
AkamaiCLI(),
20+
},
21+
}
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[default]
2+
client_secret = abcdE23FNkBxy456z25qx9Yp5CPUxlEfQeTDkfh4QA=I
3+
host = akab-lmn789n2k53w7qrs-nfkxaa4lfk3kd6ym.luna.akamaiapis.net
4+
access_token = akab-zyx987xa6osbli4k-e7jf5ikib5jknes3
5+
client_token = akab-nomoflavjuc4422e-fa2xznerxrm3teg7
6+
7+
[newcredential]
8+
client_secret = M9XGZP/D2JedcbABC4Td8XSnHfKKIV4N5n28cj2y6zE=
9+
host = akab-ip5n2k53w7nhdcxy-nflxabc432DE1ymd.luna.akamaiapis.net
10+
access_token = akab-abc77fxa6zyxi4k-e7jf5ikib5jknesc3
11+
client_token = akab-moo22awk8765efd-s2yw5zqfrx4jp57cf
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[default]
2+
client_secret = abcdE23FNkBxy456z25qx9Yp5CPUxlEfQeTDkfh4QA=I
3+
host = akab-lmn789n2k53w7qrs-nfkxaa4lfk3kd6ym.luna.akamaiapis.net
4+
access_token = akab-zyx987xa6osbli4k-e7jf5ikib5jknes3
5+
client_token = akab-nomoflavjuc4422e-fa2xznerxrm3teg7

sdk/schema/credname/names.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,28 @@ import "github.com/1Password/shell-plugins/sdk"
44

55
// Credential type names.
66
const (
7-
APIKey = sdk.CredentialName("API Key")
8-
APIToken = sdk.CredentialName("API Token")
9-
AccessKey = sdk.CredentialName("Access Key")
10-
AccessToken = sdk.CredentialName("Access Token")
11-
AppPassword = sdk.CredentialName("App Password")
12-
AppToken = sdk.CredentialName("App Token")
13-
AuthToken = sdk.CredentialName("Auth Token")
14-
CLIToken = sdk.CredentialName("CLI Token")
15-
Credential = sdk.CredentialName("Credential")
16-
Credentials = sdk.CredentialName("Credentials")
17-
DatabaseCredentials = sdk.CredentialName("Database Credentials")
18-
LoginDetails = sdk.CredentialName("Login Details")
19-
PersonalAPIToken = sdk.CredentialName("Personal API Token")
20-
PersonalAccessToken = sdk.CredentialName("Personal Access Token")
21-
RegistryCredentials = sdk.CredentialName("Registry Credentials")
22-
SecretKey = sdk.CredentialName("Secret Key")
7+
APIClientCredentials = sdk.CredentialName("API Client Credentials")
8+
APIKey = sdk.CredentialName("API Key")
9+
APIToken = sdk.CredentialName("API Token")
10+
AccessKey = sdk.CredentialName("Access Key")
11+
AccessToken = sdk.CredentialName("Access Token")
12+
AppPassword = sdk.CredentialName("App Password")
13+
AppToken = sdk.CredentialName("App Token")
14+
AuthToken = sdk.CredentialName("Auth Token")
15+
CLIToken = sdk.CredentialName("CLI Token")
16+
Credential = sdk.CredentialName("Credential")
17+
Credentials = sdk.CredentialName("Credentials")
18+
DatabaseCredentials = sdk.CredentialName("Database Credentials")
19+
LoginDetails = sdk.CredentialName("Login Details")
20+
PersonalAPIToken = sdk.CredentialName("Personal API Token")
21+
PersonalAccessToken = sdk.CredentialName("Personal Access Token")
22+
RegistryCredentials = sdk.CredentialName("Registry Credentials")
23+
SecretKey = sdk.CredentialName("Secret Key")
2324
)
2425

2526
func ListAll() []sdk.CredentialName {
2627
return []sdk.CredentialName{
28+
APIClientCredentials,
2729
APIKey,
2830
APIToken,
2931
AccessKey,

sdk/schema/fieldname/names.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const (
99
APIKeyID = sdk.FieldName("API Key ID")
1010
APISecret = sdk.FieldName("API Secret")
1111
AccessKeyID = sdk.FieldName("Access Key ID")
12+
AccessToken = sdk.FieldName("Access Token")
1213
Account = sdk.FieldName("Account")
1314
AccountID = sdk.FieldName("Account ID")
1415
AccountSID = sdk.FieldName("Account SID")
@@ -20,6 +21,8 @@ const (
2021
Authtoken = sdk.FieldName("Authtoken")
2122
Cert = sdk.FieldName("Cert")
2223
Certificate = sdk.FieldName("Certificate")
24+
ClientSecret = sdk.FieldName("Client Secret")
25+
ClientToken = sdk.FieldName("Client Token")
2326
Credential = sdk.FieldName("Credential")
2427
Credentials = sdk.FieldName("Credentials")
2528
Database = sdk.FieldName("Database")
@@ -56,6 +59,7 @@ func ListAll() []sdk.FieldName {
5659
APIKeyID,
5760
APISecret,
5861
AccessKeyID,
62+
AccessToken,
5963
Account,
6064
AccountID,
6165
AccountSID,
@@ -67,6 +71,8 @@ func ListAll() []sdk.FieldName {
6771
Authtoken,
6872
Cert,
6973
Certificate,
74+
ClientSecret,
75+
ClientToken,
7076
Credential,
7177
Credentials,
7278
Database,

0 commit comments

Comments
 (0)