Skip to content

Commit 2615828

Browse files
committed
Revert breaking edits and fix tests
It wasn't working before because the default redirectURI in the Config had been changed. cli is a predefined client in arduino authentication system that requires a certain redirectURI. Changing the redirectURI means you have to change the ClientID as well. Now the tests are run providing -user and -pass flags, in order not to leak passwords when the arduino-cli will be made public.
1 parent e5e9bb2 commit 2615828

File tree

3 files changed

+107
-128
lines changed

3 files changed

+107
-128
lines changed

auth/auth.go

+59-48
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,19 @@
2727
* Copyright 2017 BCMI LABS SA (http://www.arduino.cc/)
2828
*/
2929

30-
/*
31-
Package auth uses the `oauth2 authorization_code` flow to authenticate with Arduino
32-
33-
If you have the username and password of a user, you can just instantiate a client with sane defaults:
34-
35-
client := auth.New()
36-
37-
and then call the Token method to obtain a Token object with an AccessToken and a RefreshToken
38-
39-
token, err := client.Token(username, password)
40-
41-
If instead you already have a token but want to refresh it, just call
42-
43-
token, err := client.refresh(refreshToken)
44-
*/
30+
// Package auth uses the `oauth2 authorization_code` flow to authenticate with Arduino
31+
//
32+
// If you have the username and password of a user, you can just instantiate a client with sane defaults:
33+
//
34+
// client := auth.New()
35+
//
36+
// and then call the Token method to obtain a Token object with an AccessToken and a RefreshToken
37+
//
38+
// token, err := client.Token(username, password)
39+
//
40+
// If instead you already have a token but want to refresh it, just call
41+
//
42+
// token, err := client.refresh(refreshToken)
4543
package auth
4644

4745
import (
@@ -56,17 +54,53 @@ import (
5654
"github.com/pkg/errors"
5755
)
5856

57+
// Config contains the variables you may want to change
58+
type Config struct {
59+
// CodeURL is the endpoint to redirect to obtain a code
60+
CodeURL string
61+
62+
// TokenURL is the endpoint where you can request an access code
63+
TokenURL string
64+
65+
// ClientID is the client id you are using
66+
ClientID string
67+
68+
// RedirectURI is the redirectURI where the oauth process will redirect. It's only required since the oauth system checks for it, but we intercept the redirect before hitting it
69+
RedirectURI string
70+
71+
// Scopes is a space-separated list of scopes to require
72+
Scopes string
73+
}
74+
5975
// New returns an auth configuration with sane defaults
6076
func New() *Config {
6177
return &Config{
6278
CodeURL: "https://hydra.arduino.cc/oauth2/auth",
6379
TokenURL: "https://hydra.arduino.cc/oauth2/token",
6480
ClientID: "cli",
65-
RedirectURI: "http://auth.arduino.cc:5000",
81+
RedirectURI: "http://localhost:5000",
6682
Scopes: "profile:core offline",
6783
}
6884
}
6985

86+
// Token is the response of the two authentication functions
87+
type Token struct {
88+
// Access is the token to use to authenticate requests
89+
Access string `json:"access_token"`
90+
91+
// Refresh is the token to use to request another access token. It's only returned if one of the scopes is "offline"
92+
Refresh string `json:"refresh_token"`
93+
94+
// TTL is the number of seconds that the tokens will last
95+
TTL int `json:"expires_in"`
96+
97+
// Scopes is a space-separated list of scopes associated to the access token
98+
Scopes string `json:"scope"`
99+
100+
// Type is the type of token
101+
Type string `json:"token_type"`
102+
}
103+
70104
// Token authenticates with the given username and password and returns a Token object
71105
func (c *Config) Token(user, pass string) (*Token, error) {
72106
// We want to make sure we send the proper cookies each step, so we don't follow redirects
@@ -131,37 +165,6 @@ func (c *Config) Refresh(token string) (*Token, error) {
131165
return &data, nil
132166
}
133167

134-
type User struct{}
135-
136-
// LoggedUser returns the logged User's data.
137-
func (t *Token) LoggedUser() (*User, error) {
138-
req, err := http.NewRequest("GET", "https://auth.arduino.cc/v1/users/byID/me", nil)
139-
if err != nil {
140-
return nil, err
141-
}
142-
req.SetBasicAuth("cli", "")
143-
req.Header.Add("Authorization", "Bearer "+t.Access)
144-
client := http.Client{}
145-
resp, err := client.Do(req)
146-
if err != nil {
147-
return nil, errors.Wrap(err, "LoggedUser")
148-
}
149-
if resp.StatusCode != 200 {
150-
return nil, errors.New(resp.Status)
151-
}
152-
defer resp.Body.Close()
153-
content, err := ioutil.ReadAll(resp.Body)
154-
if err != nil {
155-
return nil, errors.Wrap(err, "LoggedUser")
156-
}
157-
var ret User
158-
err = json.Unmarshal(content, &ret)
159-
if err != nil {
160-
return nil, errors.Wrap(err, "LoggedUser")
161-
}
162-
return &ret, nil
163-
}
164-
165168
// cookies keeps track of the cookies for each request
166169
type cookies map[string][]*http.Cookie
167170

@@ -269,7 +272,7 @@ func (c *Config) requestToken(client *http.Client, code string) (*Token, error)
269272
}
270273

271274
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
272-
req.SetBasicAuth("cli", "")
275+
req.SetBasicAuth(c.ClientID, "")
273276
res, err := client.Do(req)
274277
if err != nil {
275278
return nil, err
@@ -280,6 +283,14 @@ func (c *Config) requestToken(client *http.Client, code string) (*Token, error)
280283
return nil, err
281284
}
282285

286+
if res.StatusCode != 200 {
287+
data := struct {
288+
Error string `json:"error_description"`
289+
}{}
290+
json.Unmarshal(body, &data)
291+
return nil, errors.New(data.Error)
292+
}
293+
283294
data := Token{}
284295

285296
err = json.Unmarshal(body, &data)

auth/auth_test.go

+48-23
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,64 @@
11
package auth_test
22

3-
import "testing"
4-
import "github.com/bcmi-labs/arduino-cli/auth"
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"io/ioutil"
7+
"net/http"
8+
"os"
9+
"testing"
510

6-
const (
7-
testUsername = "ARDUINO-CLI-TEST-USER"
8-
testPassword = "clitestuser"
11+
"github.com/bcmi-labs/arduino-cli/auth"
912
)
1013

11-
func testConfig_Token(t *testing.T) (*auth.Config, *auth.Token) {
12-
tokenConfig := auth.New()
13-
t.Log(tokenConfig)
14-
token, err := tokenConfig.Token(testUsername, testPassword)
14+
var (
15+
testUser = flag.String("user", "", "The username of the test")
16+
testPass = flag.String("pass", "", "The password of the test")
17+
)
18+
19+
func TestMain(m *testing.M) {
20+
flag.Parse()
21+
os.Exit(m.Run())
22+
}
23+
24+
func TestToken(t *testing.T) {
25+
if *testUser == "" || *testPass == "" {
26+
t.Skip("Skipped because -user and -pass were not provided")
27+
}
28+
auth := auth.New()
29+
token, err := auth.Token(*testUser, *testPass)
1530
if err != nil {
16-
t.Error(err)
31+
t.Fatal(err)
1732
}
18-
t.Log(token)
19-
return tokenConfig, token
20-
}
2133

22-
func TestConfig_Refresh(t *testing.T) {
23-
tokenConfig, token := testConfig_Token(t)
34+
// Obtain info
35+
req, err := http.NewRequest("GET", "https://auth.arduino.cc/v1/users/byID/me", nil)
36+
if err != nil {
37+
t.Fatal(err)
38+
}
39+
req.Header.Add("Authorization", "Bearer "+token.Access)
40+
client := http.Client{}
41+
resp, err := client.Do(req)
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
46+
if resp.StatusCode != 200 {
47+
t.Fatal(resp.StatusCode)
48+
}
2449

25-
newToken, err := tokenConfig.Refresh(token.Refresh)
50+
body, err := ioutil.ReadAll(resp.Body)
2651
if err != nil {
27-
t.Error(err)
52+
t.Fatal(err)
2853
}
29-
t.Log(newToken)
30-
}
3154

32-
func TestConfig_MyUser(t *testing.T) {
33-
_, token := testConfig_Token(t)
34-
user, err := token.LoggedUser()
55+
var data struct{ Username string }
56+
err = json.Unmarshal(body, &data)
3557
if err != nil {
3658
t.Fatal(err)
3759
}
38-
t.Log(user)
60+
61+
if data.Username != *testUser {
62+
t.Fatalf("Expected username '%s', got '%s'", *testUser, data.Username)
63+
}
3964
}

auth/token.go

-57
This file was deleted.

0 commit comments

Comments
 (0)