github.com/merlinepedra/gopphish-attack@v0.9.0/controllers/api/user_test.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"net/http/httptest"
     9  
    10  	"golang.org/x/crypto/bcrypt"
    11  
    12  	ctx "github.com/gophish/gophish/context"
    13  	"github.com/gophish/gophish/models"
    14  )
    15  
    16  func (s *APISuite) createUnpriviledgedUser(slug string) *models.User {
    17  	role, err := models.GetRoleBySlug(slug)
    18  	s.Nil(err)
    19  	unauthorizedUser := &models.User{
    20  		Username: "foo",
    21  		Hash:     "bar",
    22  		ApiKey:   "12345",
    23  		Role:     role,
    24  		RoleID:   role.ID,
    25  	}
    26  	err = models.PutUser(unauthorizedUser)
    27  	s.Nil(err)
    28  	return unauthorizedUser
    29  }
    30  
    31  func (s *APISuite) TestGetUsers() {
    32  	r := httptest.NewRequest(http.MethodGet, "/api/users", nil)
    33  	r = ctx.Set(r, "user", s.admin)
    34  	w := httptest.NewRecorder()
    35  
    36  	s.apiServer.Users(w, r)
    37  	s.Equal(w.Code, http.StatusOK)
    38  
    39  	got := []models.User{}
    40  	err := json.NewDecoder(w.Body).Decode(&got)
    41  	s.Nil(err)
    42  
    43  	// We only expect one user
    44  	s.Equal(1, len(got))
    45  	// And it should be the admin user
    46  	s.Equal(s.admin.Id, got[0].Id)
    47  }
    48  
    49  func (s *APISuite) TestCreateUser() {
    50  	payload := &userRequest{
    51  		Username: "foo",
    52  		Password: "bar",
    53  		Role:     models.RoleUser,
    54  	}
    55  	body, err := json.Marshal(payload)
    56  	s.Nil(err)
    57  
    58  	r := httptest.NewRequest(http.MethodPost, "/api/users", bytes.NewBuffer(body))
    59  	r.Header.Set("Content-Type", "application/json")
    60  	r = ctx.Set(r, "user", s.admin)
    61  	w := httptest.NewRecorder()
    62  
    63  	s.apiServer.Users(w, r)
    64  	s.Equal(w.Code, http.StatusOK)
    65  
    66  	got := &models.User{}
    67  	err = json.NewDecoder(w.Body).Decode(got)
    68  	s.Nil(err)
    69  	s.Equal(got.Username, payload.Username)
    70  	s.Equal(got.Role.Slug, payload.Role)
    71  }
    72  
    73  // TestModifyUser tests that a user with the appropriate access is able to
    74  // modify their username and password.
    75  func (s *APISuite) TestModifyUser() {
    76  	unpriviledgedUser := s.createUnpriviledgedUser(models.RoleUser)
    77  	newPassword := "new-password"
    78  	newUsername := "new-username"
    79  	payload := userRequest{
    80  		Username: newUsername,
    81  		Password: newPassword,
    82  		Role:     unpriviledgedUser.Role.Slug,
    83  	}
    84  	body, err := json.Marshal(payload)
    85  	s.Nil(err)
    86  	url := fmt.Sprintf("/api/users/%d", unpriviledgedUser.Id)
    87  	r := httptest.NewRequest(http.MethodPut, url, bytes.NewBuffer(body))
    88  	r.Header.Set("Content-Type", "application/json")
    89  	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", unpriviledgedUser.ApiKey))
    90  	w := httptest.NewRecorder()
    91  
    92  	s.apiServer.ServeHTTP(w, r)
    93  	response := &models.User{}
    94  	err = json.NewDecoder(w.Body).Decode(response)
    95  	s.Nil(err)
    96  	s.Equal(w.Code, http.StatusOK)
    97  	s.Equal(response.Username, newUsername)
    98  	got, err := models.GetUser(unpriviledgedUser.Id)
    99  	s.Nil(err)
   100  	s.Equal(response.Username, got.Username)
   101  	s.Equal(newUsername, got.Username)
   102  	err = bcrypt.CompareHashAndPassword([]byte(got.Hash), []byte(newPassword))
   103  	s.Nil(err)
   104  }
   105  
   106  // TestUnauthorizedListUsers ensures that users without the ModifySystem
   107  // permission are unable to list the users registered in Gophish.
   108  func (s *APISuite) TestUnauthorizedListUsers() {
   109  	// First, let's create a standard user which doesn't
   110  	// have ModifySystem permissions.
   111  	unauthorizedUser := s.createUnpriviledgedUser(models.RoleUser)
   112  	// We'll try to make a request to the various users API endpoints to
   113  	// ensure that they fail. Previously, we could hit the handlers directly
   114  	// but we need to go through the router for this test to ensure the
   115  	// middleware gets applied.
   116  	r := httptest.NewRequest(http.MethodGet, "/api/users/", nil)
   117  	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", unauthorizedUser.ApiKey))
   118  	w := httptest.NewRecorder()
   119  
   120  	s.apiServer.ServeHTTP(w, r)
   121  	s.Equal(w.Code, http.StatusForbidden)
   122  }
   123  
   124  // TestUnauthorizedModifyUsers verifies that users without ModifySystem
   125  // permission (a "standard" user) can only get or modify their own information.
   126  func (s *APISuite) TestUnauthorizedGetUser() {
   127  	// First, we'll make sure that a user with the "user" role is unable to
   128  	// get the information of another user (in this case, the main admin).
   129  	unauthorizedUser := s.createUnpriviledgedUser(models.RoleUser)
   130  	url := fmt.Sprintf("/api/users/%d", s.admin.Id)
   131  	r := httptest.NewRequest(http.MethodGet, url, nil)
   132  	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", unauthorizedUser.ApiKey))
   133  	w := httptest.NewRecorder()
   134  
   135  	s.apiServer.ServeHTTP(w, r)
   136  	s.Equal(w.Code, http.StatusForbidden)
   137  }
   138  
   139  // TestUnauthorizedModifyRole ensures that users without the ModifySystem
   140  // privilege are unable to modify their own role, preventing a potential
   141  // privilege escalation issue.
   142  func (s *APISuite) TestUnauthorizedSetRole() {
   143  	unauthorizedUser := s.createUnpriviledgedUser(models.RoleUser)
   144  	url := fmt.Sprintf("/api/users/%d", unauthorizedUser.Id)
   145  	payload := &userRequest{
   146  		Username: unauthorizedUser.Username,
   147  		Role:     models.RoleAdmin,
   148  	}
   149  	body, err := json.Marshal(payload)
   150  	s.Nil(err)
   151  	r := httptest.NewRequest(http.MethodPut, url, bytes.NewBuffer(body))
   152  	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", unauthorizedUser.ApiKey))
   153  	w := httptest.NewRecorder()
   154  
   155  	s.apiServer.ServeHTTP(w, r)
   156  	s.Equal(w.Code, http.StatusBadRequest)
   157  	response := &models.Response{}
   158  	err = json.NewDecoder(w.Body).Decode(response)
   159  	s.Nil(err)
   160  	s.Equal(response.Message, ErrInsufficientPermission.Error())
   161  }
   162  
   163  // TestModifyWithExistingUsername verifies that it's not possible to modify
   164  // an user's username to one which already exists.
   165  func (s *APISuite) TestModifyWithExistingUsername() {
   166  	unauthorizedUser := s.createUnpriviledgedUser(models.RoleUser)
   167  	payload := &userRequest{
   168  		Username: s.admin.Username,
   169  		Role:     unauthorizedUser.Role.Slug,
   170  	}
   171  	body, err := json.Marshal(payload)
   172  	s.Nil(err)
   173  	url := fmt.Sprintf("/api/users/%d", unauthorizedUser.Id)
   174  	r := httptest.NewRequest(http.MethodPut, url, bytes.NewReader(body))
   175  	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", unauthorizedUser.ApiKey))
   176  	w := httptest.NewRecorder()
   177  
   178  	s.apiServer.ServeHTTP(w, r)
   179  	s.Equal(w.Code, http.StatusBadRequest)
   180  	expected := &models.Response{
   181  		Message: ErrUsernameTaken.Error(),
   182  		Success: false,
   183  	}
   184  	got := &models.Response{}
   185  	err = json.NewDecoder(w.Body).Decode(got)
   186  	s.Nil(err)
   187  	s.Equal(got.Message, expected.Message)
   188  }