package ibd import ( "context" "encoding/json" "net/http" "net/url" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/net/html" ) const extractAuthHtml = ` Log in ยท Dow Jones
` func Test_extractAuthConfig(t *testing.T) { t.Parallel() expectedJSON := ` { "auth0Domain": "sso.accounts.dowjones.com", "callbackURL": "https://myibd.investors.com/oidc/callback", "clientID": "GSU1pG2Brgd3Pv2KBnAZ24zvy5uWSCQn", "extraParams": { "protocol": "oauth2", "scope": "openid idp_id roles email given_name family_name uuid djUsername djStatus trackid tags prts updated_at created_at offline_access djid", "response_type": "code", "nonce": "6402fabb-1b75-4a2c-a84f-11ad61aadb6b", "ui_locales": "en-us-x-ibd-23-7", "_csrf": "NdURgwOCuXENTEqCp8MWnmpkqwyokbcSa6U__-5boyVsSsASVNHKSA", "_intstate": "deprecated", "state": "earc7q6Rq6kyGKxy.Ymliq9N1EvoSUtz8CV8n0VAc6VsUxDIRM4SrlmIbW2k" }, "internalOptions": { "response_type": "code", "client_id": "GSU1pG2Brgd3Pv2KBnAZ24zvy5uWSCQn", "scope": "openid idp_id roles email given_name family_name uuid djUsername djStatus trackid tags prts updated_at created_at offline_access djid", "redirect_uri": "https://myibd.investors.com/oidc/callback", "ui_locales": "en-us-x-ibd-23-7", "eurl": "https://www.investors.com", "nonce": "6402fabb-1b75-4a2c-a84f-11ad61aadb6b", "state": "earc7q6Rq6kyGKxy.Ymliq9N1EvoSUtz8CV8n0VAc6VsUxDIRM4SrlmIbW2k", "resource": "https%3A%2F%2Fwww.investors.com", "protocol": "oauth2", "client": "GSU1pG2Brgd3Pv2KBnAZ24zvy5uWSCQn" }, "isThirdPartyClient": false, "authorizationServer": { "url": "https://sso.accounts.dowjones.com", "issuer": "https://sso.accounts.dowjones.com/" } }` var expectedCfg authConfig err := json.Unmarshal([]byte(expectedJSON), &expectedCfg) require.NoError(t, err) node, err := html.Parse(strings.NewReader(extractAuthHtml)) require.NoError(t, err) cfg, err := extractAuthConfig(node) require.NoError(t, err) require.NotNil(t, cfg) assert.Equal(t, expectedCfg, *cfg) } const extractTokenParamsHtml = `
` const extractTokenExpectedToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkalVzZXJuYW1lIjoiYW5zZzE5MUB5YWhvby5jb20iLCJpZCI6IjAxZWFmNTE5LTA0OWItNGIyOS04ZjZhLWQyNjIyZjNiMWJjNiIsImdpdmVuX25hbWUiOiJBbnNodWwiLCJmYW1pbHlfbmFtZSI6Ikd1cHRhIiwibmFtZSI6IkFuc2h1bCBHdXB0YSIsImVtYWlsIjoiYW5zZzE5MUB5YWhvby5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYWNjb3VudF9pZCI6Ijk5NzI5Mzc0NDIxMiIsImRqaWQiOiIwMWVhZjUxOS0wNDliLTRiMjktOGY2YS1kMjYyMmYzYjFiYzYiLCJ0cmFja2lkIjoiMWM0NGQyMTRmM2VlYTZiMzcyNDYxNDc3NDc0NDMyODJmMTRmY2ZjYmI4NmE4NmVjYTI0MDc2ZDVlMzU4ZmUzZCIsInVwZGF0ZWRfYXQiOjE3MTI3OTQxNTYsImNyZWF0ZWRfYXQiOjE3MTI3OTQxNTYsInVhdCI6MTcyMjU1MjMzOSwicm9sZXMiOlsiQkFSUk9OUy1DSEFOR0VQQVNTV09SRCIsIkZSRUVSRUctQkFTRSIsIkZSRUVSRUctSU5ESVZJRFVBTCIsIldTSi1DSEFOR0VQQVNTV09SRCIsIldTSi1BUkNISVZFIiwiV1NKLVNFTEZTRVJWIiwiSUJELUlORElWSURVQUwiLCJJQkQtSUNBIiwiSUJELUFFSSJdLCJkalN0YXR1cyI6WyJJQkRfVVNFUlMiXSwicHJ0cyI6IjIwMjQwNDEwMTcwOTE2LTA0MDAiLCJjcmVhdGVUaW1lc3RhbXAiOiIyMDI0MDQxMTAwMDkxNloiLCJzdXVpZCI6Ik1ERmxZV1kxTVRrdE1EUTVZaTAwWWpJNUxUaG1ObUV0WkRJMk1qSm1NMkl4WW1NMi50S09fM014VkVReks3dE5qTkdxUXNZMlBNbXp5cUxGRkxySnBrZGhrcDZrIiwic3ViIjoiMDFlYWY1MTktMDQ5Yi00YjI5LThmNmEtZDI2MjJmM2IxYmM2IiwiYXVkIjoiR1NVMXBHMkJyZ2QzUHYyS0JuQVoyNHp2eTV1V1NDUW4iLCJpc3MiOiJodHRwczovL3Nzby5hY2NvdW50cy5kb3dqb25lcy5jb20vIiwiaWF0IjoxNzIyNTUyMzM5MTI0LCJleHAiOjE3MjI1NTI3NzExMjR9.HVn33IFttQrG1JKEV2oElIy3mm8TJ-3GpV_jqZE81_cY22z4IMWPz7zUGz0WgOoUuQGyrYXiaNrfxD6GaoimRL6wxrH0Fy5iYC3dOEdlGfldswfgEOwSiZkBJRc2wWTVQLm93EeJ5ZZyKIXGY_ZkwcYfhrwaTAz8McBBnRmZkm0eiNJQ5YK-QZL-yFa3DxMdPPW91jLA2rjOIVnJ-I_0nMwaJ4ZwXHG2Sw4aAXxtbFqIqarKwIdOUSpRFOCSYpeWcxmbliurKlP1djrKrYgYSZxsKOHZhnbikZDtoDCAlPRlfbKOO4u36KXooDYGJ6p__s2kGCLOLLkP_QLHMNU8Jg" const extractTokenExpectedParams = "%7B%22response_type%22%3A%22code%22%2C%22client_id%22%3A%22GSU1pG2Brgd3Pv2KBnAZ24zvy5uWSCQn%22%2C%22redirect_uri%22%3A%22https%3A%2F%2Fmyibd.investors.com%2Foidc%2Fcallback%22%2C%22state%22%3A%22J-ihUYZIYzey682D.aOLszineC9qjPkM6Y6wWgFC61ABYBiuK9u48AHTFS5I%22%2C%22scope%22%3A%22openid%20idp_id%20roles%20email%20given_name%20family_name%20uuid%20djUsername%20djStatus%20trackid%20tags%20prts%20updated_at%20created_at%20offline_access%20djid%22%2C%22nonce%22%3A%22457bb517-f490-43b6-a55f-d93f90d698ad%22%7D" func Test_extractTokenParams(t *testing.T) { t.Parallel() node, err := html.Parse(strings.NewReader(extractTokenParamsHtml)) require.NoError(t, err) token, params, err := extractTokenParams(node) require.NoError(t, err) assert.Equal(t, extractTokenExpectedToken, token) assert.Equal(t, extractTokenExpectedParams, params) } func TestClient_Authenticate(t *testing.T) { t.Parallel() expectedVal := "test-cookie" expectedExp := time.Now().Add(time.Hour).Round(time.Second).In(time.UTC) server := newServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { uri := r.URL.String() switch uri { case signInUrl: w.Header().Set("Content-Type", "text/html") _, err := w.Write([]byte(extractAuthHtml)) require.NoError(t, err) return case authenticateUrl: var body authRequestBody require.NoError(t, json.NewDecoder(r.Body).Decode(&body)) assert.Equal(t, "abc", body.Username) assert.Equal(t, "xyz", body.Password) w.Header().Set("Content-Type", "text/html") _, err := w.Write([]byte(extractTokenParamsHtml)) require.NoError(t, err) return case postAuthUrl: require.NoError(t, r.ParseForm()) assert.Equal(t, extractTokenExpectedToken, r.Form.Get("token")) params, err := url.QueryUnescape(extractTokenExpectedParams) require.NoError(t, err) assert.Equal(t, params, r.Form.Get("params")) w.Header().Set("Content-Type", "text/html") http.SetCookie(w, &http.Cookie{Name: cookieName, Value: expectedVal, Expires: expectedExp}) _, err = w.Write([]byte("OK")) require.NoError(t, err) return default: t.Fatalf("unexpected URL: %s", uri) } })) client, err := NewClient(http.DefaultClient, apiKey, nil, "", WithBaseURL(server.URL)) require.NoError(t, err) cookie, err := client.Authenticate(context.Background(), "abc", "xyz") require.NoError(t, err) require.NotNil(t, cookie) assert.Equal(t, expectedVal, cookie.Value) assert.Equal(t, expectedExp, cookie.Expires) } func TestClient_Authenticate_401(t *testing.T) { t.Parallel() server := newServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { uri := r.URL.String() switch uri { case signInUrl: w.Header().Set("Content-Type", "text/html") _, err := w.Write([]byte(extractAuthHtml)) require.NoError(t, err) return case authenticateUrl: var body authRequestBody require.NoError(t, json.NewDecoder(r.Body).Decode(&body)) assert.Equal(t, "abc", body.Username) assert.Equal(t, "xyz", body.Password) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusUnauthorized) _, err := w.Write([]byte(`{"name":"ValidationError","code":"ERR016","message":"Wrong username or password","description":"Wrong username or password"}`)) require.NoError(t, err) return default: t.Fatalf("unexpected URL: %s", uri) } })) client, err := NewClient(http.DefaultClient, apiKey, nil, "", WithBaseURL(server.URL)) require.NoError(t, err) cookie, err := client.Authenticate(context.Background(), "abc", "xyz") assert.Nil(t, cookie) assert.ErrorIs(t, err, ErrBadCredentials) }