github.com/google/go-github/v33@v33.0.0/test/integration/authorizations_test.go (about) 1 // Copyright 2016 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 // +build integration 7 8 package integration 9 10 import ( 11 "context" 12 "math/rand" 13 "os" 14 "strconv" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/google/go-github/v33/github" 20 ) 21 22 const msgEnvMissing = "Skipping test because the required environment variable (%v) is not present." 23 const envKeyGitHubUsername = "GITHUB_USERNAME" 24 const envKeyGitHubPassword = "GITHUB_PASSWORD" 25 const envKeyClientID = "GITHUB_CLIENT_ID" 26 const envKeyClientSecret = "GITHUB_CLIENT_SECRET" 27 const envKeyAccessToken = "GITHUB_ACCESS_TOKEN" 28 const InvalidTokenValue = "iamnotacroken" 29 30 // TestAuthorizationsAppOperations tests the application/token related operations, such 31 // as creating, testing, resetting and revoking application OAuth tokens. 32 func TestAuthorizationsAppOperations(t *testing.T) { 33 34 appAuthenticatedClient := getOAuthAppClient(t) 35 36 // We know these vars are set because getOAuthAppClient would have 37 // skipped the test by now 38 clientID := os.Getenv(envKeyClientID) 39 accessToken := os.Getenv(envKeyAccessToken) 40 41 // Verify the token 42 appAuth, resp, err := appAuthenticatedClient.Authorizations.Check(context.Background(), clientID, accessToken) 43 failOnError(t, err) 44 failIfNotStatusCode(t, resp, 200) 45 46 // Quick sanity check 47 if *appAuth.Token != accessToken { 48 t.Fatal("The returned auth/token does not match.") 49 } 50 51 // Let's verify that we get a 404 for a non-existent token 52 _, resp, err = appAuthenticatedClient.Authorizations.Check(context.Background(), clientID, InvalidTokenValue) 53 if err == nil { 54 t.Fatal("An error should have been returned because of the invalid token.") 55 } 56 failIfNotStatusCode(t, resp, 404) 57 58 // Let's reset the token 59 resetAuth, resp, err := appAuthenticatedClient.Authorizations.Reset(context.Background(), clientID, accessToken) 60 failOnError(t, err) 61 failIfNotStatusCode(t, resp, 200) 62 63 // Let's verify that we get a 404 for a non-existent token 64 _, resp, err = appAuthenticatedClient.Authorizations.Reset(context.Background(), clientID, InvalidTokenValue) 65 if err == nil { 66 t.Fatal("An error should have been returned because of the invalid token.") 67 } 68 failIfNotStatusCode(t, resp, 404) 69 70 // Verify that the token has changed 71 if *resetAuth.Token == accessToken { 72 t.Fatal("The reset token should be different from the original.") 73 } 74 75 // Verify that we do have a token value 76 if *resetAuth.Token == "" { 77 t.Fatal("A token value should have been returned.") 78 } 79 80 // Verify that the original token is now invalid 81 _, resp, err = appAuthenticatedClient.Authorizations.Check(context.Background(), clientID, accessToken) 82 if err == nil { 83 t.Fatal("The original token should be invalid.") 84 } 85 failIfNotStatusCode(t, resp, 404) 86 87 // Check that the reset token is valid 88 _, resp, err = appAuthenticatedClient.Authorizations.Check(context.Background(), clientID, *resetAuth.Token) 89 failOnError(t, err) 90 failIfNotStatusCode(t, resp, 200) 91 92 // Let's revoke the token 93 resp, err = appAuthenticatedClient.Authorizations.Revoke(context.Background(), clientID, *resetAuth.Token) 94 failOnError(t, err) 95 failIfNotStatusCode(t, resp, 204) 96 97 // Sleep for two seconds... I've seen cases where the revocation appears not 98 // to have take place immediately. 99 time.Sleep(time.Second * 2) 100 101 // Now, the reset token should also be invalid 102 _, resp, err = appAuthenticatedClient.Authorizations.Check(context.Background(), clientID, *resetAuth.Token) 103 if err == nil { 104 t.Fatal("The reset token should be invalid.") 105 } 106 failIfNotStatusCode(t, resp, 404) 107 } 108 109 // generatePersonalAuthTokenRequest is a helper function that generates an 110 // AuthorizationRequest for a Personal Access Token (no client id). 111 func generatePersonalAuthTokenRequest() *github.AuthorizationRequest { 112 113 rand := randString() 114 auth := github.AuthorizationRequest{ 115 Note: github.String("Personal token: Note generated by test: " + rand), 116 Scopes: []github.Scope{github.ScopePublicRepo}, 117 Fingerprint: github.String("Personal token: Fingerprint generated by test: " + rand), 118 } 119 120 return &auth 121 } 122 123 // generatePersonalAuthTokenRequest is a helper function that generates an 124 // AuthorizationRequest for an OAuth application Token (uses client id). 125 func generateAppAuthTokenRequest(clientID string, clientSecret string) *github.AuthorizationRequest { 126 127 rand := randString() 128 auth := github.AuthorizationRequest{ 129 Note: github.String("App token: Note generated by test: " + rand), 130 Scopes: []github.Scope{github.ScopePublicRepo}, 131 Fingerprint: github.String("App token: Fingerprint generated by test: " + rand), 132 ClientID: github.String(clientID), 133 ClientSecret: github.String(clientSecret), 134 } 135 136 return &auth 137 } 138 139 // randString returns a (kinda) random string for uniqueness purposes. 140 func randString() string { 141 return strconv.FormatInt(rand.NewSource(time.Now().UnixNano()).Int63(), 10) 142 } 143 144 // failOnError invokes t.Fatal() if err is present. 145 func failOnError(t *testing.T, err error) { 146 147 if err != nil { 148 t.Fatal(err) 149 } 150 } 151 152 // failIfNotStatusCode invokes t.Fatal() if the response's status code doesn't match the expected code. 153 func failIfNotStatusCode(t *testing.T, resp *github.Response, expectedCode int) { 154 155 if resp.StatusCode != expectedCode { 156 t.Fatalf("Expected HTTP status code [%v] but received [%v]", expectedCode, resp.StatusCode) 157 } 158 159 } 160 161 // getUserPassClient returns a GitHub client for authorization testing. The client 162 // uses BasicAuth via GH username and password passed in environment variables 163 // (and will skip the calling test if those vars are not present). 164 func getUserPassClient(t *testing.T) *github.Client { 165 username, ok := os.LookupEnv(envKeyGitHubUsername) 166 if !ok { 167 t.Skipf(msgEnvMissing, envKeyGitHubUsername) 168 } 169 170 password, ok := os.LookupEnv(envKeyGitHubPassword) 171 if !ok { 172 t.Skipf(msgEnvMissing, envKeyGitHubPassword) 173 } 174 175 tp := github.BasicAuthTransport{ 176 Username: strings.TrimSpace(username), 177 Password: strings.TrimSpace(password), 178 } 179 180 return github.NewClient(tp.Client()) 181 } 182 183 // getOAuthAppClient returns a GitHub client for authorization testing. The client 184 // uses BasicAuth, but instead of username and password, it uses the client id 185 // and client secret passed in via environment variables 186 // (and will skip the calling test if those vars are not present). Certain API operations (check 187 // an authorization; reset an authorization; revoke an authorization for an app) 188 // require this authentication mechanism. 189 // 190 // See GitHub API docs: https://developer.com/v3/oauth_authorizations/#check-an-authorization 191 func getOAuthAppClient(t *testing.T) *github.Client { 192 193 username, ok := os.LookupEnv(envKeyClientID) 194 if !ok { 195 t.Skipf(msgEnvMissing, envKeyClientID) 196 } 197 198 password, ok := os.LookupEnv(envKeyClientSecret) 199 if !ok { 200 t.Skipf(msgEnvMissing, envKeyClientSecret) 201 } 202 203 tp := github.BasicAuthTransport{ 204 Username: strings.TrimSpace(username), 205 Password: strings.TrimSpace(password), 206 } 207 208 return github.NewClient(tp.Client()) 209 }