Skip to content

Commit

Permalink
Secured New Public User
Browse files Browse the repository at this point in the history
Can't create user from public user if not public organisation or email not authorized.
Added methods to allow creation of organisation+owner to init new organisation chat.
  • Loading branch information
titouanfreville committed Mar 11, 2017
1 parent ac0b614 commit c8de2db
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 5 deletions.
103 changes: 101 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"net/http"
"os"
"regexp"

jwt "github.com/dgrijalva/jwt-go"
"github.com/jinzhu/gorm"
Expand Down Expand Up @@ -40,6 +41,7 @@ type key string
// }

var (
secret string
hmacSampleSecret []byte
tokenAuth *JwtAuth
userToken *jwt.Token
Expand All @@ -63,9 +65,23 @@ func newRandomString(length int) string {
return b.String()
}
func initAuth() {
secret := newRandomString(100)
hmacSampleSecret = []byte(secret)
tokenAuth = New("HS256", hmacSampleSecret, hmacSampleSecret)
claims := jwt.MapClaims{
"organisation_name": "PopCube",
"organisation_stack": 1,
"organisation_domain": "chat.popcube.xyz",
"public": false,
"owner": "TCMJJ",
"owner_mail": "[email protected]",
"owner_password": "popcube",
"type": "neworganisation",
"authorise": "this token let you create new organisation and a new user in an iner DB",
}
unsignedToken := *jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, _ := unsignedToken.SignedString(hmacSampleSecret)
log.Print("Tolken new organisation && role : ")
log.Print(tokenString)
}

// createUserToken create JWT auth token for current login user
Expand Down Expand Up @@ -168,7 +184,19 @@ func basicRoutes(router *chi.Mux) {
// 404: incorrectIds
// 422: wrongEntity
// 503: databaseError
// default: genericError
router.Post("/login", loginMiddleware)
// swagger:route POST /initorganisation Init initOrganisation
//
// Try to log user in
//
// Login user with provided USERNAME && Password
//
// Responses:
// 200: initOk
// 503: databaseError
// default: genericError
router.Post("/initorganisation", initOrganisation)
router.Route("/publicuser", func(r chi.Router) {
// swagger:route POST /publicuser/new Users newPublicUser
//
Expand Down Expand Up @@ -258,16 +286,86 @@ func loginMiddleware(w http.ResponseWriter, r *http.Request) {

}

func initOrganisation(w http.ResponseWriter, r *http.Request) {
// Verify token
ctx := r.Context()
if jwtErr, ok := ctx.Value(jwtErrorKey).(error); ok {
if jwtErr != nil {
render.JSON(w, 401, jwtErr)
return
}
}
jwtToken, ok := ctx.Value(jwtTokenKey).(*jwt.Token)
if !ok || jwtToken == nil || !jwtToken.Valid {
render.JSON(w, 401, "token is not valid or does not exist")
return
}
tokenType, ok := jwtToken.Claims.(jwt.MapClaims)["type"]
if !ok {
render.JSON(w, 401, "Token is not valid. Type is undifined")
return
}
if tokenType != "neworganisation" {
render.JSON(w, 401, "Token is not an init organisation one")
return
}
// Token passed. Initialising organisation
store := datastores.Store()
db := dbStore.db
organisation := models.Organisation{
OrganisationName: jwtToken.Claims.(jwt.MapClaims)["organisation_name"].(string),
DockerStack: jwtToken.Claims.(jwt.MapClaims)["organisation_stack"].(int),
Domain: jwtToken.Claims.(jwt.MapClaims)["organisation_domain"].(string),
Public: jwtToken.Claims.(jwt.MapClaims)["public"].(bool),
}
user := models.User{
Username: jwtToken.Claims.(jwt.MapClaims)["owner"].(string),
Email: jwtToken.Claims.(jwt.MapClaims)["owner_mail"].(string),
Password: jwtToken.Claims.(jwt.MapClaims)["owner_password"].(string),
// Owner role should always have ID 1 as it is the first one created into the DB.
IDRole: 1,
}
if err := db.DB().Ping(); err != nil {
render.JSON(w, error503.StatusCode, error503)
return
}
appErr := store.Organisation().Save(&organisation, db)
if appErr != nil {
render.JSON(w, appErr.StatusCode, appErr)
return
}
appErr = store.User().Save(&user, db)
if appErr != nil {
render.JSON(w, appErr.StatusCode, appErr)
return
}
res := initOk{
Organisation: organisation,
Owner: user,
}
render.JSON(w, 201, res)
}

func newPublicUser(w http.ResponseWriter, r *http.Request) {
var data struct {
User *models.User
OmitID interface{} `json:"id,omitempty"`
}
store := datastores.Store()

db := dbStore.db
request := r.Body
err := chiRender.Bind(request, &data)
organisation := store.Organisation().Get(db)
allowedWebMails := store.AllowedWebMails().GetAll(db)
isAuthorizedMail := false
for _, authorizedMail := range allowedWebMails {
filter := "*" + authorizedMail.Domain
ok, _ := regexp.MatchString(filter, data.User.Email)
isAuthorizedMail = isAuthorizedMail || ok
}
if !isAuthorizedMail && !organisation.Public {
render.JSON(w, 401, "You can't sign up if organisation is not public or your email domain was unauthorized.")
}
if err != nil || data.User == nil {
render.JSON(w, error422.StatusCode, error422)
} else {
Expand All @@ -287,6 +385,7 @@ func newPublicUser(w http.ResponseWriter, r *http.Request) {
// StartAPI initialise the api with provided host and port.
func StartAPI(hostname string, port string, DbConnectionInfo *configs.DbConnection) {
router := newRouter()
_, _, secret = configs.InitConfig()
// Init DB connection
user := DbConnectionInfo.User
db := DbConnectionInfo.Database
Expand Down
10 changes: 10 additions & 0 deletions api/api_responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ type inviteOk struct {
Token string `json:"token,omitempty"`
}

// initOk when init correctly proceed, return the organisation object and its owner.
//
// swagger:response loginOk
type initOk struct {
// in:body
Organisation models.Organisation `json:"organisation,omitempty"`
// in:body
Owner models.User `json:"user,omitempty"`
}

// ---------------------------------------------------
// Errors --------------------------------------------

Expand Down
11 changes: 9 additions & 2 deletions configs/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type APIServerInfo struct {
}

// InitConfig get configuration for project
func InitConfig() (DbConnection, APIServerInfo) {
func InitConfig() (DbConnection, APIServerInfo, string) {
// Default configurations
dbConnection := DbConnection{
User: "root",
Expand All @@ -34,11 +34,18 @@ func InitConfig() (DbConnection, APIServerInfo) {
Hostname: "",
Port: "3000",
}
// Dev secret
secret := "AAAAB3NzaC1yc2EAAAADAQABAAACAQCtdGt4uK8e1CEcTVZXSRJ9pRHxdeYBxq4oTh20DKH7exoikkEPbSAn34ZJPVVRdPMndg8Qg5xxHnwAtYvzYbxNWAxqYqvvvCKLJtjTS2dMeNLVz3FYD80MSJX3Tr5gpK7hHq9EEWB99onqMKDHlF3ZM3dBjwZH3mP7sWlqcdKc6lP9MGPsrpnXmBx3C4CSB7muMl8hF+4263gtS1oXHT0E16NFP3IgBNmvYavmOYSlqHs9NU7lZtNVbLbIZ2SCVrOJlcSKddvaMzIhXgRIK58VzbsqqaeVBTMrxrJopjLha2aTSe9luxOJZCf1foQKVf7eWPp4FK/zSSDMJbSX6+vsE1jFbuFF2dYmf8QW1UdDslZtQuCLzB4rqBmOiFx77DIyuZMMt5bjTi02nPYZL5Fo4vupcoV552QC6jyUG3nAoY28yPGmhKBb0EpbCd/qiroIAs5mXhaPGZriqq8DDRbqstHkubfXjDkZ6vWRDnCUfSioMky/bEC1X2KaMt/E0tpw8aWiIZXAble+CIWfo2HUj2GE/Y3Gf8f/A14Ec2E+Uz4xARcTL4UfopNU2P3Bxhz/KoIZFXYacKBphATsp+HB6sMKF5HJ+tn6mS0JFdgIpcClVMliap4zz6M92FOyyRW0wBHua6gOI+5nEMS2BDLBwTmw5otXOTFV8DaFNQzaiQ"
// Default host for DB in Docker containers
if os.Getenv("ENVTYPE") == "container" {
log.Print("<><><><> Setting host to container default \n")
dbConnection.Host = "database"
}

if newSecret := os.Getenv("POPCUBESECRET"); newSecret != "" {
secret = newSecret
}

// Get values set in env
if apiPort := os.Getenv("API_PORT"); apiPort != "" {
log.Print("<><><><> Setting api port \n")
Expand Down Expand Up @@ -73,5 +80,5 @@ func InitConfig() (DbConnection, APIServerInfo) {
}

// Return new configs
return dbConnection, APIServer
return dbConnection, APIServer, secret
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
)

func getConf(dbSettings *configs.DbConnection, serverSetting *configs.APIServerInfo) {
*dbSettings, *serverSetting = configs.InitConfig()
*dbSettings, *serverSetting, _ = configs.InitConfig()
}

func initAPI() {
Expand Down

0 comments on commit c8de2db

Please sign in to comment.