From c56df01274a91ff730018dcd6272423a3e1593f0 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Tue, 11 Feb 2020 13:43:01 +0100 Subject: [feat] expose auth API in pkg/vpn Be able to check if it needs auth and then be able to login. Use the logged in token for fetching the cert. --- pkg/bitmask/bitmask.go | 2 ++ pkg/vpn/bonafide/auth.go | 3 +-- pkg/vpn/bonafide/auth_anon.go | 28 ++----------------- pkg/vpn/bonafide/auth_sip.go | 34 ++---------------------- pkg/vpn/bonafide/bonafide.go | 59 ++++++++++++++++++++++++++--------------- pkg/vpn/bonafide/eip_service.go | 2 +- pkg/vpn/main.go | 8 ++++++ 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/pkg/bitmask/bitmask.go b/pkg/bitmask/bitmask.go index df26fc0..927e486 100644 --- a/pkg/bitmask/bitmask.go +++ b/pkg/bitmask/bitmask.go @@ -28,4 +28,6 @@ type Bitmask interface { ListGateways(provider string) ([]string, error) UseGateway(name string) error UseTransport(transport string) error + NeedsCredentials() bool + DoLogin(username, password string) (bool, error) } diff --git a/pkg/vpn/bonafide/auth.go b/pkg/vpn/bonafide/auth.go index 62d3d8f..5a97b3f 100644 --- a/pkg/vpn/bonafide/auth.go +++ b/pkg/vpn/bonafide/auth.go @@ -25,6 +25,5 @@ type credentials struct { type authentication interface { needsCredentials() bool - getToken(cred *credentials) ([]byte, error) - getPemCertificate(cred *credentials) ([]byte, error) + getToken(user, password string) ([]byte, error) } diff --git a/pkg/vpn/bonafide/auth_anon.go b/pkg/vpn/bonafide/auth_anon.go index 3a666a8..8a55e3a 100644 --- a/pkg/vpn/bonafide/auth_anon.go +++ b/pkg/vpn/bonafide/auth_anon.go @@ -17,40 +17,16 @@ package bonafide import ( "errors" - "fmt" - "io/ioutil" ) type anonymousAuthentication struct { - client httpClient - authURI string - certURI string + client httpClient } func (a *anonymousAuthentication) needsCredentials() bool { return true } -func (a *anonymousAuthentication) getPemCertificate(cred *credentials) ([]byte, error) { - resp, err := a.client.Post(certAPI, "", nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode == 404 { - resp, err = a.client.Post(certAPI3, "", nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - } - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Get vpn cert has failed with status: %s", resp.Status) - } - - return ioutil.ReadAll(resp.Body) -} - -func (a *anonymousAuthentication) getToken(cred *credentials) ([]byte, error) { +func (a *anonymousAuthentication) getToken(user, password string) ([]byte, error) { return []byte(""), errors.New("anon authentication should not call getToken") } diff --git a/pkg/vpn/bonafide/auth_sip.go b/pkg/vpn/bonafide/auth_sip.go index b7ab0c8..1bfef52 100644 --- a/pkg/vpn/bonafide/auth_sip.go +++ b/pkg/vpn/bonafide/auth_sip.go @@ -26,34 +26,18 @@ import ( type sipAuthentication struct { client httpClient authURI string - certURI string } func (a *sipAuthentication) needsCredentials() bool { return true } -func (a *sipAuthentication) getPemCertificate(cred *credentials) ([]byte, error) { - if cred == nil { - return nil, fmt.Errorf("Need bonafide credentials for sip auth") - } - token, err := a.getToken(cred) - if err != nil { - return nil, fmt.Errorf("Error while getting token: %s", err) - } - cert, err := a.getProtectedCert(a.certURI, string(token)) - if err != nil { - return nil, fmt.Errorf("Error while getting cert: %s", err) - } - return cert, nil -} - -func (a *sipAuthentication) getToken(cred *credentials) ([]byte, error) { +func (a *sipAuthentication) getToken(user, password string) ([]byte, error) { /* TODO [ ] get token from disk? [ ] check if expired? set a goroutine to refresh it periodically? */ - credJSON, err := formatCredentials(cred.User, cred.Password) + credJSON, err := formatCredentials(user, password) if err != nil { return nil, fmt.Errorf("Cannot encode credentials: %s", err) } @@ -68,20 +52,6 @@ func (a *sipAuthentication) getToken(cred *credentials) ([]byte, error) { return ioutil.ReadAll(resp.Body) } -func (a *sipAuthentication) getProtectedCert(uri, token string) ([]byte, error) { - req, err := http.NewRequest("POST", uri, strings.NewReader("")) - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) - resp, err := a.client.Do(req) - if err != nil { - return nil, fmt.Errorf("Error while getting token: %s", err) - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return nil, fmt.Errorf("Error %d", resp.StatusCode) - } - return ioutil.ReadAll(resp.Body) -} - func formatCredentials(user, pass string) (string, error) { c := credentials{User: user, Password: pass} credJSON, err := json.Marshal(c) diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go index 1b48276..4561eb1 100644 --- a/pkg/vpn/bonafide/bonafide.go +++ b/pkg/vpn/bonafide/bonafide.go @@ -25,6 +25,7 @@ import ( "io/ioutil" "log" "net/http" + "strings" "time" "0xacab.org/leap/bitmask-vpn/pkg/config" @@ -50,7 +51,7 @@ type Bonafide struct { eip *eipService tzOffsetHours int auth authentication - credentials credentials + token []byte apiURL string } @@ -101,28 +102,29 @@ func New() *Bonafide { switch auth := config.Auth; auth { case "sip": log.Println("Client expects sip auth") - b.auth = &sipAuthentication{client, b.getURL("auth"), b.getURL("certv3")} + b.auth = &sipAuthentication{client, b.getURL("auth")} case "anon": log.Println("Client expects anon auth") - b.auth = &anonymousAuthentication{client, "", b.getURL("certv3")} + b.auth = &anonymousAuthentication{client} default: log.Println("Client expects invalid auth", auth) - b.auth = &anonymousAuthentication{client, "", b.getURL("certv3")} + b.auth = &anonymousAuthentication{client} } return b } +func (b *Bonafide) NeedsCredentials() bool { + return b.auth.needsCredentials() +} + func (b *Bonafide) DoLogin(username, password string) (bool, error) { if !b.auth.needsCredentials() { return false, errors.New("Auth method does not need login") } - cred := credentials{username, password} - b.credentials = cred - - /* TODO keep this in memory */ - _, err := b.auth.getToken(&cred) + var err error + b.token, err = b.auth.getToken(username, password) if err != nil { return false, err } @@ -130,24 +132,39 @@ func (b *Bonafide) DoLogin(username, password string) (bool, error) { return true, nil } -func (b *Bonafide) checkCredentialsAreSet() bool { - if b.credentials.User == "" || b.credentials.Password == "" { - log.Println("BUG: expected credentials to be set") - return false - } - return true -} - func (b *Bonafide) GetPemCertificate() ([]byte, error) { if b.auth == nil { log.Fatal("ERROR: bonafide did not initialize auth") } - if b.auth.needsCredentials() { - b.checkCredentialsAreSet() + if b.auth.needsCredentials() && b.token == nil { + log.Println("BUG: expected token to be set, but is not there") + return nil, errors.New("Needs to login, but it was not logged in. Please, restart the application and report it if it continues happening") + } + + req, err := http.NewRequest("POST", b.getURL("certv3"), strings.NewReader("")) + if err != nil { + return nil, err + } + if b.token != nil { + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", b.token)) + } + resp, err := b.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode == 404 { + resp, err = b.client.Post(b.getURL("cert"), "", nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("Get vpn cert has failed with status: %s", resp.Status) } - cert, err := b.auth.getPemCertificate(&b.credentials) - return cert, err + return ioutil.ReadAll(resp.Body) } func (b *Bonafide) getURL(object string) string { diff --git a/pkg/vpn/bonafide/eip_service.go b/pkg/vpn/bonafide/eip_service.go index 618eda4..ff73da9 100644 --- a/pkg/vpn/bonafide/eip_service.go +++ b/pkg/vpn/bonafide/eip_service.go @@ -73,7 +73,7 @@ func (b *Bonafide) setupAuthentication(i interface{}) { case "anon": // Do nothing, we're set on initialization. case "sip": - b.auth = &sipAuthentication{b.client, b.getURL("auth"), b.getURL("certv3")} + b.auth = &sipAuthentication{b.client, b.getURL("auth")} default: log.Printf("BUG: unknown authentication method %s", auth) } diff --git a/pkg/vpn/main.go b/pkg/vpn/main.go index 4bf4395..de8e61f 100644 --- a/pkg/vpn/main.go +++ b/pkg/vpn/main.go @@ -92,3 +92,11 @@ func (b *Bitmask) Close() { func (b *Bitmask) Version() (string, error) { return "", nil } + +func (b *Bitmask) NeedsCredentials() bool { + return b.bonafide.NeedsCredentials() +} + +func (b *Bitmask) DoLogin(username, password string) (bool, error) { + return b.bonafide.DoLogin(username, password) +} -- cgit v1.2.3