ソースを参照

Merge branch 'master' into login-integration

sunguroku 5 年 前
コミット
b41fd7000c

+ 1 - 1
.gitignore

@@ -1,3 +1,3 @@
 .DS_Store
 .env
-app
+app

+ 68 - 0
docs/API.md

@@ -10,6 +10,8 @@
   - [`GET /api/users/{id}/clusters`](#get-apiusersidclusters)
   - [`GET /api/users/{id}/clusters/all`](#get-apiusersidclustersall)
   - [`POST /api/users`](#post-apiusers)
+  - [`POST /api/login`](#post-apilogin)
+  - [`POST /api/logout`](#post-apilogout)
   - [`PUT /api/users/{id}`](#put-apiusersid)
   - [`DELETE /api/users/{id}`](#delete-apiusersid)
 
@@ -285,6 +287,72 @@ User{
     }
     ```
 
+#### `POST /api/login`
+
+**Description:** Logs a user in via email and password.
+
+**URL parameters:** N/A
+
+**Query parameters:** N/A
+
+**Request Body**: 
+
+```js
+{
+    "email": String,
+    "password": String,
+}
+```
+
+**Successful Response Body**: N/A
+
+**Successful Status Code**: `200`
+
+**Errors:**
+
+- Email not registered
+  - Status Code: `401`
+  - Request Body:
+    ```json
+    {
+        "code": 401,
+        "errors": ["email not registered"]
+    }
+    ```
+
+- Incorrect password
+  - Status Code: `401`
+  - Request Body:
+    ```json
+    {
+        "code":401,
+        "errors":["incorrect password"]
+    }
+    ```
+
+#### `POST /api/logout`
+
+**Description:** Logs a user out by detaching a user from the cookie-based session. 
+
+**URL parameters:** N/A
+
+**Query parameters:** N/A
+
+**Request Body**: N/A
+
+**Successful Response Body**: N/A
+
+**Successful Status Code**: `200`
+
+**Errors:**
+
+- Not logged in
+  - Status Code: `403`
+  - Request Body:
+    ```sh
+    "Forbidden"
+    ```
+
 #### `PUT /api/users/{id}`
 
 **Description:** Updates an existing user.

+ 0 - 62
internal/auth/example/authExample.go

@@ -1,62 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"net/http"
-
-	"github.com/porter-dev/porter/internal/config"
-	"github.com/porter-dev/porter/internal/repository/gorm"
-
-	dbConn "github.com/porter-dev/porter/internal/adapter"
-	sessionstore "github.com/porter-dev/porter/internal/auth"
-)
-
-var appConf = config.FromEnv()
-
-var db, dbErr = dbConn.New(&appConf.Db)
-
-var (
-	store, _ = sessionstore.NewStore(gorm.NewRepository(db), appConf.Server)
-)
-
-func secret(w http.ResponseWriter, r *http.Request) {
-
-	session, _ := store.Get(r, "cookie-name")
-	fmt.Println(session.Values["authenticated"])
-
-	// Check if user is authenticated
-	if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
-		http.Error(w, "Forbidden", http.StatusForbidden)
-		return
-	}
-
-	// Print secret message
-	fmt.Fprintln(w, "The cake is a lie!")
-}
-
-func login(w http.ResponseWriter, r *http.Request) {
-	session, _ := store.Get(r, "cookie-name")
-
-	// Authentication goes here
-	// ...
-
-	// Set user as authenticated
-	session.Values["authenticated"] = true
-	session.Save(r, w)
-}
-
-func logout(w http.ResponseWriter, r *http.Request) {
-	session, _ := store.Get(r, "cookie-name")
-
-	// Revoke users authentication
-	session.Values["authenticated"] = false
-	session.Save(r, w)
-}
-
-func main() {
-	http.HandleFunc("/secret", secret)
-	http.HandleFunc("/login", login)
-	http.HandleFunc("/logout", logout)
-
-	http.ListenAndServe(":8080", nil)
-}

+ 14 - 0
server/api/user_handler.go

@@ -118,6 +118,20 @@ func (app *App) HandleLoginUser(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 }
 
+// HandleLogoutUser detaches the user from the session
+func (app *App) HandleLogoutUser(w http.ResponseWriter, r *http.Request) {
+	session, err := app.store.Get(r, app.cookieName)
+
+	if err != nil {
+		app.handleErrorDataRead(err, ErrUserDataRead, w)
+	}
+
+	session.Values["authenticated"] = false
+	session.Values["user_id"] = nil
+	session.Save(r, w)
+	w.WriteHeader(http.StatusOK)
+}
+
 // HandleReadUser returns an externalized User (models.UserExternal)
 // based on an ID
 func (app *App) HandleReadUser(w http.ResponseWriter, r *http.Request) {

+ 45 - 0
server/api/user_handler_test.go

@@ -339,6 +339,51 @@ func TestHandleLoginUser(t *testing.T) {
 	testUserRequests(t, loginUserTests, true)
 }
 
+var logoutUserTests = []*userTest{
+	&userTest{
+		initializers: []func(tester *tester){
+			initUserDefault,
+		},
+		msg:      "Logout user successful",
+		method:   "POST",
+		endpoint: "/api/logout",
+		body: `{
+			"email": "belanger@getporter.dev",
+			"password": "hello"
+		}`,
+		expStatus: http.StatusOK,
+		expBody:   ``,
+		useCookie: true,
+		validators: []func(c *userTest, tester *tester, t *testing.T){
+			func(c *userTest, tester *tester, t *testing.T) {
+				req, err := http.NewRequest(
+					"GET",
+					"/api/users/1",
+					strings.NewReader(""),
+				)
+
+				req.AddCookie(tester.cookie)
+
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				rr2 := httptest.NewRecorder()
+				tester.router.ServeHTTP(rr2, req)
+
+				if status := rr2.Code; status != http.StatusForbidden {
+					t.Errorf("%s, handler returned wrong status: got %v want %v",
+						"validator failed", status, http.StatusForbidden)
+				}
+			},
+		},
+	},
+}
+
+func TestHandleLogoutUser(t *testing.T) {
+	testUserRequests(t, logoutUserTests, true)
+}
+
 var readUserTests = []*userTest{
 	&userTest{
 		initializers: []func(tester *tester){

+ 1 - 0
server/router/router.go

@@ -27,6 +27,7 @@ func New(a *api.App, store *sessionstore.PGStore, cookieName string) *chi.Mux {
 		r.Method("DELETE", "/users/{id}", auth.DoesUserIDMatch(requestlog.NewHandler(a.HandleDeleteUser, l)))
 		r.Method("POST", "/login", requestlog.NewHandler(a.HandleLoginUser, l))
 		r.Method("GET", "/auth/check", requestlog.NewHandler(a.HandleAuthCheck, l))
+		r.Method("POST", "/logout", auth.BasicAuthenticate(requestlog.NewHandler(a.HandleLogoutUser, l)))
 	})
 
 	return r