-
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.
Merge pull request #36 from titouanfreville/issue-30-secureAPI
Issue 30 secure api
- Loading branch information
Showing
27 changed files
with
2,540 additions
and
268 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
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 |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
"log" | ||
"net/http" | ||
"os" | ||
"regexp" | ||
|
||
jwt "github.com/dgrijalva/jwt-go" | ||
"github.com/jinzhu/gorm" | ||
|
@@ -40,6 +41,7 @@ type key string | |
// } | ||
|
||
var ( | ||
secret string | ||
hmacSampleSecret []byte | ||
tokenAuth *JwtAuth | ||
userToken *jwt.Token | ||
|
@@ -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 | ||
|
@@ -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 | ||
// | ||
|
@@ -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 { | ||
|
@@ -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 | ||
|
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
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,97 @@ | ||
package datastores | ||
|
||
import ( | ||
"github.com/jinzhu/gorm" | ||
"github.com/titouanfreville/popcubeapi/models" | ||
u "github.com/titouanfreville/popcubeapi/utils" | ||
) | ||
|
||
// AllowedWebMailsStoreImpl Used to implement AllowedWebMailsStore interface | ||
type AllowedWebMailsStoreImpl struct{} | ||
|
||
// AllowedWebMails Generate the struct for allowedWebMails store | ||
func (s StoreImpl) AllowedWebMails() AllowedWebMailsStore { | ||
return AllowedWebMailsStoreImpl{} | ||
} | ||
|
||
// Save Use to save allowedWebMails in DB | ||
func (asi AllowedWebMailsStoreImpl) Save(allowedWebMails *models.AllowedWebMails, db *gorm.DB) *u.AppError { | ||
transaction := db.Begin() | ||
if appError := allowedWebMails.IsValid(); appError != nil { | ||
transaction.Rollback() | ||
return u.NewAPIError(422, appError.ID, "Wrong data provided : \n ---- "+appError.Message+" ----") | ||
} | ||
if !transaction.NewRecord(&allowedWebMails) { | ||
transaction.Rollback() | ||
return u.NewAPIError(409, "duplicate entry", "You already authorized "+allowedWebMails.Domain+" mails to sign up.") | ||
} | ||
if err := transaction.Create(&allowedWebMails).Error; err != nil { | ||
transaction.Rollback() | ||
return u.NewAPIError(500, "unxepected error", "Unexpected error while adding entry. \n ---- "+err.Error()+"----") | ||
} | ||
transaction.Commit() | ||
return nil | ||
} | ||
|
||
// Update Used to update allowedWebMails in DB | ||
func (asi AllowedWebMailsStoreImpl) Update(allowedWebMails *models.AllowedWebMails, newAllowedWebMails *models.AllowedWebMails, db *gorm.DB) *u.AppError { | ||
transaction := db.Begin() | ||
if appError := allowedWebMails.IsValid(); appError != nil { | ||
transaction.Rollback() | ||
return u.NewAPIError(422, appError.ID, "Wrong data provided : \n ---- "+appError.Message+" ----") | ||
} | ||
// if appError := newAllowedWebMails.IsValid(); appError != nil { | ||
// transaction.Rollback() | ||
// return u.NewLocAppError("allowedWebMailsStoreImpl.Update.allowedWebMailsNew.PreSave", appError.ID, nil, appError.DetailedError) | ||
// } | ||
if err := transaction.Model(&allowedWebMails).Updates(&newAllowedWebMails).Error; err != nil { | ||
transaction.Rollback() | ||
return u.NewAPIError(500, "unxepected error", "Unexpected error while adding entry. \n ---- "+err.Error()+"----") | ||
} | ||
transaction.Commit() | ||
return nil | ||
} | ||
|
||
// GetAll Used to get allowedWebMails from DB | ||
func (asi AllowedWebMailsStoreImpl) GetAll(db *gorm.DB) []models.AllowedWebMails { | ||
allowedWebMailss := []models.AllowedWebMails{} | ||
db.Find(&allowedWebMailss) | ||
return allowedWebMailss | ||
} | ||
|
||
// GetByID Used to get allowedWebMails from DB | ||
func (asi AllowedWebMailsStoreImpl) GetByID(ID uint64, db *gorm.DB) models.AllowedWebMails { | ||
allowedWebMails := models.AllowedWebMails{} | ||
db.Where("idAllowedWebMails = ?", ID).First(&allowedWebMails) | ||
return allowedWebMails | ||
} | ||
|
||
// GetByDomain Used to get allowedWebMails having providing domin | ||
func (asi AllowedWebMailsStoreImpl) GetByDomain(domain string, db *gorm.DB) models.AllowedWebMails { | ||
allowedWebMails := models.AllowedWebMails{} | ||
db.Where("domain = ?", domain).First(&allowedWebMails) | ||
return allowedWebMails | ||
} | ||
|
||
// GetByProvider Used to get allowedWebMails provided by ... | ||
func (asi AllowedWebMailsStoreImpl) GetByProvider(provider string, db *gorm.DB) []models.AllowedWebMails { | ||
allowedWebMails := []models.AllowedWebMails{} | ||
db.Where("provider = ?", provider).First(&allowedWebMails) | ||
return allowedWebMails | ||
|
||
} | ||
|
||
// Delete Used to remove specified allowedWebMails from DB | ||
func (asi AllowedWebMailsStoreImpl) Delete(allowedWebMails *models.AllowedWebMails, db *gorm.DB) *u.AppError { | ||
transaction := db.Begin() | ||
if appError := allowedWebMails.IsValid(); appError != nil { | ||
transaction.Rollback() | ||
return u.NewLocAppError("allowedWebMailsStoreImpl.Delete.allowedWebMails.PreSave", appError.ID, nil, appError.DetailedError) | ||
} | ||
if err := transaction.Delete(&allowedWebMails).Error; err != nil { | ||
transaction.Rollback() | ||
return u.NewLocAppError("allowedWebMailsStoreImpl.Delete", "update.transaction.delete.encounterError :"+err.Error(), nil, "") | ||
} | ||
transaction.Commit() | ||
return nil | ||
} |
Oops, something went wrong.