Fix Audi authentication and align with VW
This commit is contained in:
parent
d43f503474
commit
cf4f62cccb
3 changed files with 40 additions and 117 deletions
|
|
@ -1,15 +1,10 @@
|
|||
package vehicle
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -36,10 +31,7 @@ func init() {
|
|||
registry.Add("audi", NewAudiFromConfig)
|
||||
}
|
||||
|
||||
// AudiHashSecret is used for obtaining the X-QMauth header hash value from the current timestamp
|
||||
var AudiHashSecret = "not contained in repo due to legal concerns"
|
||||
|
||||
const audiOAuthClientID = "77869e21-e30a-4a92-b016-48ab7d3db1d8"
|
||||
const audiClientID = "77869e21-e30a-4a92-b016-48ab7d3db1d8"
|
||||
|
||||
// NewAudiFromConfig creates a new vehicle
|
||||
func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
||||
|
|
@ -91,88 +83,39 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
}
|
||||
|
||||
func (v *Audi) authFlow() error {
|
||||
var err error
|
||||
var uri string
|
||||
var req *http.Request
|
||||
var resp *http.Response
|
||||
var tokens vw.Tokens
|
||||
|
||||
const clientID = "09b6cbec-cd19-4589-82fd-363dfa8c24da@apps_vw-dilab_com"
|
||||
const clientIDAlias = "934928ef" // "09b6cbec-cd19-4589-82fd-363dfa8c24da@apps_vw-dilab_com"
|
||||
const redirectURI = "myaudi:///"
|
||||
|
||||
query := url.Values(map[string][]string{
|
||||
"response_type": {"code"},
|
||||
"response_type": {"id_token token"},
|
||||
"client_id": {clientID},
|
||||
"redirect_uri": {redirectURI},
|
||||
"scope": {"address profile badge birthdate birthplace nationalIdentifier nationality profession email vin phone nickname name picture mbb gallery openid"},
|
||||
"state": {"7f8260b5-682f-4db8-b171-50a5189a1c08"},
|
||||
"nonce": {"7f8260b5-682f-4db8-b171-50a5189a1c08"},
|
||||
"scope": {"openid profile mbb vin badge birthdate nickname email address phone name picture"},
|
||||
"state": {vw.RandomString(43)},
|
||||
"nonce": {vw.RandomString(43)},
|
||||
"prompt": {"login"},
|
||||
"ui_locales": {"de-DE"},
|
||||
})
|
||||
|
||||
uri = "https://identity.vwgroup.io/oidc/v1/authorize?" + query.Encode()
|
||||
if err == nil {
|
||||
identity := &vw.Identity{Client: v.Client}
|
||||
resp, err = identity.Login(uri, v.user, v.password)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
var code string
|
||||
if location, err := url.Parse(resp.Header.Get("Location")); err == nil {
|
||||
code = location.Query().Get("code")
|
||||
}
|
||||
|
||||
data := url.Values(map[string][]string{
|
||||
"client_id": {clientID},
|
||||
"grant_type": {"authorization_code"},
|
||||
"code": {code},
|
||||
"redirect_uri": {redirectURI},
|
||||
"response_type": {"token id_token"},
|
||||
})
|
||||
|
||||
var hash string
|
||||
secret, err := hex.DecodeString(AudiHashSecret)
|
||||
if err == nil {
|
||||
// timestamp rounded to 100s precision
|
||||
ts := strconv.FormatInt(time.Now().Unix()/100, 10)
|
||||
|
||||
mac := hmac.New(sha256.New, secret)
|
||||
_, err = mac.Write([]byte(ts))
|
||||
|
||||
hash = fmt.Sprintf("v1:%s:%0x", clientIDAlias, mac.Sum(nil))
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
uri = "https://app-api.my.audi.com/myaudiappidk/v1/emea/token"
|
||||
req, err = request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-QMAuth": hash,
|
||||
})
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if err = v.DoJSON(req, &tokens); err == nil && tokens.IDToken == "" {
|
||||
err = errors.New("missing id token (1)")
|
||||
}
|
||||
}
|
||||
}
|
||||
identity := &vw.Identity{Client: v.Client}
|
||||
idToken, err := identity.Login(query, v.user, v.password)
|
||||
|
||||
if err == nil {
|
||||
data := url.Values(map[string][]string{
|
||||
"grant_type": {"id_token"},
|
||||
"scope": {"sc2:fal"},
|
||||
"token": {tokens.IDToken},
|
||||
"token": {idToken},
|
||||
})
|
||||
|
||||
req, err = request.New(http.MethodPost, vw.OauthTokenURI, strings.NewReader(data.Encode()), map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-Client-Id": audiOAuthClientID,
|
||||
"X-Client-Id": audiClientID,
|
||||
})
|
||||
if err == nil {
|
||||
if err = v.DoJSON(req, &v.tokens); err == nil && tokens.IDToken == "" {
|
||||
err = errors.New("missing id token (2)")
|
||||
if err = v.DoJSON(req, &v.tokens); err == nil && v.tokens.AccessToken == "" {
|
||||
err = errors.New("missing access token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -185,6 +128,6 @@ func (v *Audi) refreshHeaders() map[string]string {
|
|||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-App-Version": "3.14.0",
|
||||
"X-App-Name": "myAudi",
|
||||
"X-Client-Id": audiOAuthClientID,
|
||||
"X-Client-Id": audiClientID,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,60 +82,24 @@ func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
}
|
||||
|
||||
func (v *VW) authFlow() error {
|
||||
var err error
|
||||
var uri string
|
||||
var req *http.Request
|
||||
var resp *http.Response
|
||||
var idToken string
|
||||
|
||||
// execute login
|
||||
challenge, verifier, err := vw.ChallengeVerifier()
|
||||
const clientID = "9496332b-ea03-4091-a224-8c746b885068@apps_vw-dilab_com"
|
||||
const redirectURI = "carnet://identity-kit/login"
|
||||
|
||||
query := url.Values(map[string][]string{
|
||||
"prompt": {"login"},
|
||||
"state": {vw.RandomString(43)},
|
||||
"response_type": {"code id_token token"},
|
||||
"code_challenge_method": {"s256"},
|
||||
"response_type": {"id_token token"},
|
||||
"client_id": {clientID},
|
||||
"redirect_uri": {redirectURI},
|
||||
"scope": {"openid profile mbb cars birthdate nickname address phone"},
|
||||
"code_challenge": {challenge},
|
||||
"redirect_uri": {"carnet://identity-kit/login"},
|
||||
"client_id": {"9496332b-ea03-4091-a224-8c746b885068@apps_vw-dilab_com"},
|
||||
"state": {vw.RandomString(43)},
|
||||
"nonce": {vw.RandomString(43)},
|
||||
"prompt": {"login"},
|
||||
})
|
||||
|
||||
uri = "https://identity.vwgroup.io/oidc/v1/authorize?" + query.Encode()
|
||||
if err == nil {
|
||||
identity := &vw.Identity{Client: v.Client}
|
||||
resp, err = identity.Login(uri, v.user, v.password)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// var code string
|
||||
|
||||
loc := strings.ReplaceAll(resp.Header.Get("Location"), "#", "?") // convert to parsable url
|
||||
if locationURL, err := url.Parse(loc); err == nil {
|
||||
// code = locationURL.Query().Get("code")
|
||||
idToken = locationURL.Query().Get("id_token")
|
||||
}
|
||||
|
||||
_ = verifier
|
||||
// if err == nil {
|
||||
// data := url.Values(map[string][]string{
|
||||
// "auth_code": {code},
|
||||
// "code_verifier": {verifier},
|
||||
// "id_token": {idToken},
|
||||
// })
|
||||
|
||||
// uri := "https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode"
|
||||
// req, err = request.New(http.MethodPost, uri, strings.NewReader(data.Encode()), request.URLEncoding)
|
||||
|
||||
// // if err == nil {
|
||||
// // err = v.DoJSON(req, &tokens)
|
||||
// // if err == nil && tokens.AccessToken == "" {
|
||||
// // err = errors.New("missing access token")
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
identity := &vw.Identity{Client: v.Client}
|
||||
idToken, err := identity.Login(query, v.user, v.password)
|
||||
|
||||
// get client id
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package vw
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
|
@ -51,11 +52,12 @@ func (v *Identity) redirect(resp *http.Response, err error) (*http.Response, err
|
|||
}
|
||||
|
||||
// Login performs the identity.vwgroup.io login
|
||||
func (v *Identity) Login(uri, user, password string) (*http.Response, error) {
|
||||
func (v *Identity) Login(query url.Values, user, password string) (string, error) {
|
||||
var vars FormVars
|
||||
var req *http.Request
|
||||
|
||||
// GET identity.vwgroup.io/oidc/v1/authorize?ui_locales=de&scope=openid%20profile%20birthdate%20nickname%20address%20phone%20cars%20mbb&response_type=code&state=gmiJOaB4&redirect_uri=https%3A%2F%2Fwww.portal.volkswagen-we.com%2Fportal%2Fweb%2Fguest%2Fcomplete-login&nonce=38042ee3-b7a7-43cf-a9c1-63d2f3f2d9f3&prompt=login&client_id=b7a5bb47-f875-47cf-ab83-2ba3bf6bb738@apps_vw-dilab_com
|
||||
uri := "https://identity.vwgroup.io/oidc/v1/authorize?" + query.Encode()
|
||||
resp, err := v.Get(uri)
|
||||
|
||||
// GET identity.vwgroup.io/signin-service/v1/signin/b7a5bb47-f875-47cf-ab83-2ba3bf6bb738@apps_vw-dilab_com?relayState=15404cb51c8b4cc5efeee1d2c2a73e5b41562faa
|
||||
|
|
@ -124,5 +126,19 @@ func (v *Identity) Login(uri, user, password string) (*http.Response, error) {
|
|||
resp, err = v.redirect(resp, err)
|
||||
}
|
||||
|
||||
return resp, err
|
||||
var idToken string
|
||||
if err == nil {
|
||||
loc := strings.ReplaceAll(resp.Header.Get("Location"), "#", "?") // convert to parseable url
|
||||
|
||||
var location *url.URL
|
||||
if location, err = url.Parse(loc); err == nil {
|
||||
idToken = location.Query().Get("id_token")
|
||||
|
||||
if idToken == "" {
|
||||
err = errors.New("missing id token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idToken, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue