forked from techschool/simplebank
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Bastien DUMONT
committed
Nov 6, 2024
1 parent
234b69a
commit 63c7336
Showing
15 changed files
with
307 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Varaiales for local http calls | ||
HTTP_ACCESS_TOKEN=v2.local.Jo_5B_CEfcV4OhjsFHGECiufNE65S2vyKAF0mcLtyUYKNTS24Kb1_DIDqGDHNQAkxgKrUDd3cSCRD8tUKlWSQ6TU7U1tKWpf_SFaP90-MK8HS7T0CIMKesc0WdSodrrmjNpj5xOIx36xeidckV_3qyQwDABVqUovPsrTAZhL6AnueTx2sCKZTE0k3hwQQvamywkuc0IuQ2CnebzqlH7sBJKvq9sqo2GQ3iEGW_XD9mtLsCESiaR-oJsYraa1M_Ch8HRSqZT7GGu0rpHlWVOSIprr4g.bnVsbA |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
### create account | ||
POST http://localhost:8080/accounts | ||
Content-Type: application/json | ||
Authorization: Bearer {{$dotenv HTTP_ACCESS_TOKEN}} | ||
|
||
{ | ||
"owner": "John Doe", | ||
"currency": "EUR" | ||
} | ||
|
||
### get account | ||
GET http://localhost:8080/accounts/120 | ||
Authorization: Bearer {{$dotenv HTTP_ACCESS_TOKEN}} | ||
|
||
### list accounts | ||
GET http://localhost:8080/accounts?page_id=1&page_size=5 | ||
Authorization: Bearer {{$dotenv HTTP_ACCESS_TOKEN}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package api | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/bastiendmt/simplebank/token" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
const ( | ||
authorizationHeaderKey = "authorization" | ||
authorizationTypeBearer = "bearer" | ||
authorizationPayloadKey = "access_payload" | ||
) | ||
|
||
// AuthMiddleware creates a gin middleware for authorization | ||
func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc { | ||
return func(ctx *gin.Context) { | ||
authorizationHeader := ctx.GetHeader(authorizationHeaderKey) | ||
|
||
if len(authorizationHeader) == 0 { | ||
err := errors.New("authorization header is not provided") | ||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err)) | ||
return | ||
} | ||
|
||
fields := strings.Fields(authorizationHeader) | ||
if len(fields) < 2 { | ||
err := errors.New("invalid authorization header format") | ||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err)) | ||
return | ||
} | ||
|
||
authorizationType := strings.ToLower(fields[0]) | ||
if authorizationType != authorizationTypeBearer { | ||
err := fmt.Errorf("unsupported authorization type %s", authorizationType) | ||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err)) | ||
return | ||
} | ||
|
||
accessToken := fields[1] | ||
payload, err := tokenMaker.VerifyToken(accessToken) | ||
if err != nil { | ||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err)) | ||
return | ||
} | ||
|
||
ctx.Set(authorizationPayloadKey, payload) | ||
ctx.Next() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package api | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
|
||
"github.com/bastiendmt/simplebank/token" | ||
"github.com/gin-gonic/gin" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func addAuthorization( | ||
t *testing.T, | ||
request *http.Request, | ||
tokenMaker token.Maker, | ||
authorizationType string, | ||
username string, | ||
role string, | ||
duration time.Duration, | ||
) { | ||
token, payload, err := tokenMaker.CreateToken(username, duration) | ||
require.NoError(t, err) | ||
require.NotEmpty(t, payload) | ||
|
||
authorizationHeader := fmt.Sprintf("%s %s", authorizationType, token) | ||
request.Header.Set(authorizationHeaderKey, authorizationHeader) | ||
} | ||
|
||
func TestAuthMiddleware(t *testing.T) { | ||
username := "username" | ||
role := "" | ||
|
||
testCases := []struct { | ||
name string | ||
setupAuth func(t *testing.T, request *http.Request, tokenMaker token.Maker) | ||
checkResponse func(t *testing.T, recorder *httptest.ResponseRecorder) | ||
}{ | ||
{ | ||
name: "OK", | ||
setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { | ||
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, username, role, time.Minute) | ||
}, | ||
checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { | ||
require.Equal(t, http.StatusOK, recorder.Code) | ||
}, | ||
}, | ||
{ | ||
name: "NoAuthorization", | ||
setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { | ||
}, | ||
checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { | ||
require.Equal(t, http.StatusUnauthorized, recorder.Code) | ||
}, | ||
}, | ||
{ | ||
name: "UnsupportedAuthorization", | ||
setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { | ||
addAuthorization(t, request, tokenMaker, "unsupported", username, role, time.Minute) | ||
}, | ||
checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { | ||
require.Equal(t, http.StatusUnauthorized, recorder.Code) | ||
}, | ||
}, | ||
{ | ||
name: "InvalidAuthorizationFormat", | ||
setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { | ||
addAuthorization(t, request, tokenMaker, "", username, role, time.Minute) | ||
}, | ||
checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { | ||
require.Equal(t, http.StatusUnauthorized, recorder.Code) | ||
}, | ||
}, | ||
{ | ||
name: "ExpiredToken", | ||
setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { | ||
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, username, role, -time.Minute) | ||
}, | ||
checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { | ||
require.Equal(t, http.StatusUnauthorized, recorder.Code) | ||
}, | ||
}, | ||
} | ||
|
||
for i := range testCases { | ||
tc := testCases[i] | ||
|
||
t.Run(tc.name, func(t *testing.T) { | ||
server := newTestServer(t, nil) | ||
authPath := "/auth" | ||
server.router.GET( | ||
authPath, | ||
authMiddleware(server.tokenMaker), | ||
func(ctx *gin.Context) { | ||
ctx.JSON(http.StatusOK, gin.H{}) | ||
}, | ||
) | ||
|
||
recorder := httptest.NewRecorder() | ||
request, err := http.NewRequest(http.MethodGet, authPath, nil) | ||
require.NoError(t, err) | ||
|
||
tc.setupAuth(t, request, server.tokenMaker) | ||
server.router.ServeHTTP(recorder, request) | ||
tc.checkResponse(t, recorder) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.