//ValidateUsername checks if a username is already taken or not
func (service *Service) ValidateUsername(w http.ResponseWriter, request *http.Request) {
	username := request.URL.Query().Get("username")
	response := struct {
		Valid bool   `json:"valid"`
		Error string `json:"error"`
	}{
		Valid: true,
		Error: "",
	}
	valid := user.ValidateUsername(username)
	if !valid {
		log.Debug("Invalid username format:", username)
		response.Error = "invalid_username_format"
		response.Valid = false
		json.NewEncoder(w).Encode(&response)
		return
	}
	userMgr := user.NewManager(request)
	userExists, err := userMgr.Exists(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if userExists {
		log.Debug("username ", username, " already taken")
		response.Error = "duplicate_username"
		response.Valid = false
	}
	json.NewEncoder(w).Encode(&response)
	return
}
// DeleteDigitalAssetAddress is the handler for DELETE /users/{username}/digitalwallet/{label}
func (api UsersAPI) DeleteDigitalAssetAddress(w http.ResponseWriter, r *http.Request) {
	username := mux.Vars(r)["username"]
	label := mux.Vars(r)["label"]
	userMgr := user.NewManager(r)

	u, err := userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	_, err = u.GetDigitalAssetAddressByLabel(label)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	if err = userMgr.RemoveVirtualCurrency(username, label); err != nil {
		log.Error("ERROR while saving address:\n", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
Example #3
0
//LoginResendPhonenumberConfirmation resend the phone number confirmation after logging in to a possibly new phone number
func (service *Service) LoginResendPhonenumberConfirmation(w http.ResponseWriter, request *http.Request) {
	values := struct {
		PhoneNumber string `json:"phonenumber"`
	}{}

	response := struct {
		Error string `json:"error"`
	}{}

	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the ResendPhonenumberConfirmation request: ", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	loginSession, err := service.GetSession(request, SessionLogin, "loginsession")
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if loginSession.IsNew {
		sessions.Save(request, w)
		log.Debug("Login session expired")
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}

	username, _ := loginSession.Values["username"].(string)

	//Invalidate the previous validation request, ignore a possible error
	validationkey, _ := loginSession.Values["phonenumbervalidationkey"].(string)
	_ = service.phonenumberValidationService.ExpireValidation(request, validationkey)

	phonenumber := user.Phonenumber{Label: "main", Phonenumber: values.PhoneNumber}
	if !phonenumber.IsValid() {
		log.Debug("Invalid phone number")
		w.WriteHeader(422)
		response.Error = "invalid_phonenumber"
		json.NewEncoder(w).Encode(&response)
		return
	}

	uMgr := user.NewManager(request)
	err = uMgr.SavePhone(username, phonenumber)
	if err != nil {
		log.Error("ResendPhonenumberConfirmation: Could not save phonenumber: ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	validationkey, err = service.phonenumberValidationService.RequestValidation(request, username, phonenumber, fmt.Sprintf("https://%s/phonevalidation", request.Host))
	if err != nil {
		log.Error("ResendPhonenumberConfirmation: Could not get validationkey: ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	loginSession.Values["phonenumbervalidationkey"] = validationkey
	sessions.Save(request, w)
	w.WriteHeader(http.StatusNoContent)
}
Example #4
0
//FilterAuthorizedScopes filters the requested scopes to the ones that are authorizated, if no authorization exists, authorizedScops is nil
func (service *Service) FilterAuthorizedScopes(r *http.Request, username string, grantedTo string, requestedscopes []string) (authorizedScopes []string, err error) {
	authorization, err := userdb.NewManager(r).GetAuthorization(username, grantedTo)
	if authorization == nil || err != nil {
		return
	}

	authorizedScopes = authorization.FilterAuthorizedScopes(requestedscopes)

	return
}
// UpdateDigitalAssetAddress is the handler for PUT /users/{username}/digitalwallet/{label}
// Update the label and/or value of an existing address.
func (api UsersAPI) UpdateDigitalAssetAddress(w http.ResponseWriter, r *http.Request) {
	username := mux.Vars(r)["username"]
	oldlabel := mux.Vars(r)["label"]

	newcurrency := user.DigitalAssetAddress{}
	if err := json.NewDecoder(r.Body).Decode(&newcurrency); err != nil {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	if !isValidLabel(newcurrency.Label) {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	userMgr := user.NewManager(r)

	u, err := userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	_, err = u.GetDigitalAssetAddressByLabel(oldlabel)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	if oldlabel != newcurrency.Label {
		_, err = u.GetAddressByLabel(newcurrency.Label)
		if err == nil {
			http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
			return
		}
	}

	if err = userMgr.SaveVirtualCurrency(username, newcurrency); err != nil {
		log.Error("ERROR while saving address - ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	if oldlabel != newcurrency.Label {
		if err := userMgr.RemoveVirtualCurrency(username, oldlabel); err != nil {
			log.Error(err)
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
	}
	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(newcurrency)
}
Example #6
0
//ForgotPassword handler for POST /login/forgotpassword
func (service *Service) ForgotPassword(w http.ResponseWriter, request *http.Request) {
	// login can be username or email
	values := struct {
		Login string `json:"login"`
	}{}

	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the ForgotPassword request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	userMgr := user.NewManager(request)
	valMgr := validationdb.NewManager(request)
	validatedemail, err := valMgr.GetByEmailAddressValidatedEmailAddress(values.Login)
	if err != nil && err != mgo.ErrNotFound {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
	var username string
	var emails []string
	if err != mgo.ErrNotFound {
		username = validatedemail.Username
		emails = []string{validatedemail.EmailAddress}
	} else {
		user, err := userMgr.GetByName(values.Login)
		if err != nil && err != mgo.ErrNotFound {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
		username = user.Username
		validatedemails, err := valMgr.GetByUsernameValidatedEmailAddress(username)
		if validatedemails == nil || len(validatedemails) == 0 {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
		if err != nil {
			log.Error("Failed to get validated emails address - ", err)
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		}
		emails = make([]string, len(validatedemails))
		for idx, validatedemail := range validatedemails {
			emails[idx] = validatedemail.EmailAddress
		}

	}
	_, err = service.emailaddressValidationService.RequestPasswordReset(request, username, emails)
	if err != nil {
		log.Error("Failed to request password reset - ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
	w.WriteHeader(http.StatusNoContent)
	return
}
Example #7
0
//GetSmsCode returns an sms code for a specified phone label
func (service *Service) GetSmsCode(w http.ResponseWriter, request *http.Request) {
	phoneLabel := mux.Vars(request)["phoneLabel"]
	loginSession, err := service.GetSession(request, SessionLogin, "loginsession")
	if err != nil {
		log.Error("Error getting login session", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	sessionInfo, err := newLoginSessionInformation()
	if err != nil {
		log.Error("Error creating login session information", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	username, ok := loginSession.Values["username"].(string)
	if username == "" || !ok {
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}
	userMgr := user.NewManager(request)
	userFromDB, err := userMgr.GetByName(username)
	if err != nil {
		log.Error("Error getting user", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	phoneNumber, err := userFromDB.GetPhonenumberByLabel(phoneLabel)
	if err != nil {
		log.Debug(userFromDB.Phonenumbers)
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	loginSession.Values["sessionkey"] = sessionInfo.SessionKey
	authClientId := loginSession.Values["auth_client_id"]
	authenticatingOrganization := ""
	if authClientId != nil {
		authenticatingOrganization = authClientId.(string)
	}
	mgoCollection := db.GetCollection(db.GetDBSession(request), mongoLoginCollectionName)
	mgoCollection.Insert(sessionInfo)
	organizationText := ""
	if authenticatingOrganization != "" {
		split := strings.Split(authenticatingOrganization, ".")
		organizationText = fmt.Sprintf("to authorize the organization %s, ", split[len(split)-1])
	}
	smsmessage := fmt.Sprintf("To continue signing in at itsyou.online %senter the code %s in the form or use this link: https://%s/sc?c=%s&k=%s",
		organizationText, sessionInfo.SMSCode, request.Host, sessionInfo.SMSCode, url.QueryEscape(sessionInfo.SessionKey))
	sessions.Save(request, w)
	go service.smsService.Send(phoneNumber.Phonenumber, smsmessage)
	w.WriteHeader(http.StatusNoContent)
}
// RegisterNewDigitalAssetAddress is the handler for POST /users/{username}/digitalwallet
// Register a new address
func (api UsersAPI) RegisterNewDigitalAssetAddress(w http.ResponseWriter, r *http.Request) {
	username := mux.Vars(r)["username"]
	userMgr := user.NewManager(r)

	currency := user.DigitalAssetAddress{}

	if err := json.NewDecoder(r.Body).Decode(&currency); err != nil {
		log.Debug("Error while decoding the body: ", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	if !isValidLabel(currency.Label) {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	u, err := userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	//Check if this label is already used
	_, err = u.GetDigitalAssetAddressByLabel(currency.Label)
	if err == nil {
		http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
		return
	}

	if err := userMgr.SaveVirtualCurrency(username, currency); err != nil {
		log.Error("ERROR while saving virtual currency:\n", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	u, err = userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	newWallet := u.DigitalWallet

	// respond with created phone number.
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)

	json.NewEncoder(w).Encode(newWallet)
}
Example #9
0
// GetTwoFactorAuthenticationMethods returns the possible two factor authentication methods the user can use to login with.
func (service *Service) GetTwoFactorAuthenticationMethods(w http.ResponseWriter, request *http.Request) {
	loginSession, err := service.GetSession(request, SessionLogin, "loginsession")
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	username, ok := loginSession.Values["username"].(string)
	if username == "" || !ok {
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}
	userMgr := user.NewManager(request)
	userFromDB, err := userMgr.GetByName(username)
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	response := struct {
		Totp bool              `json:"totp"`
		Sms  map[string]string `json:"sms"`
	}{Sms: make(map[string]string)}
	totpMgr := totp.NewManager(request)
	response.Totp, err = totpMgr.HasTOTP(username)
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	valMgr := validationdb.NewManager(request)
	verifiedPhones, err := valMgr.GetByUsernameValidatedPhonenumbers(username)
	if err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	for _, validatedPhoneNumber := range verifiedPhones {
		for _, number := range userFromDB.Phonenumbers {
			if number.Phonenumber == string(validatedPhoneNumber.Phonenumber) {
				response.Sms[number.Label] = string(validatedPhoneNumber.Phonenumber)
			}
		}
	}
	json.NewEncoder(w).Encode(response)
	return
}
// GetDigitalWallet is handler for GET /users/{username}/digitalwallet
func (api UsersAPI) GetDigitalWallet(w http.ResponseWriter, r *http.Request) {
	username := mux.Vars(r)["username"]
	userMgr := user.NewManager(r)

	useobj, err := userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	if len(useobj.DigitalWallet) == 0 {
		useobj.DigitalWallet = make([]user.DigitalAssetAddress, 0)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(useobj.DigitalWallet)
}
// GetDigitalAssetAddress It is handler for GET /users/{username}/digitalwallet/{label}
func (api UsersAPI) GetDigitalAssetAddress(w http.ResponseWriter, r *http.Request) {
	username := mux.Vars(r)["username"]
	label := mux.Vars(r)["label"]
	userMgr := user.NewManager(r)

	userobj, err := userMgr.GetByName(username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	currency, err := userobj.GetDigitalAssetAddressByLabel(label)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(currency)
}
func SearchUser(r *http.Request, searchString string) (usr *user.User, err1 error) {
	userMgr := user.NewManager(r)
	usr, err1 = userMgr.GetByName(searchString)
	if err1 == mgo.ErrNotFound {
		valMgr := validationdb.NewManager(r)
		validatedPhonenumber, err2 := valMgr.GetByPhoneNumber(searchString)
		if err2 == mgo.ErrNotFound {
			validatedEmailAddress, err3 := valMgr.GetByEmailAddress(searchString)
			if err3 != nil {
				return nil, err3
			} else {
				return userMgr.GetByName(validatedEmailAddress.Username)
			}
		} else {
			return userMgr.GetByName(validatedPhonenumber.Username)
		}
	} else {
		return usr, err1
	}
}
func (service *Service) GithubCallback(w http.ResponseWriter, request *http.Request) {
	var code = request.URL.Query().Get("code")
	// Get GitHub access token
	clientId, err := identityservice.GetOauthClientID("github")
	log.Info("clientId")
	log.Info(clientId)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	clientSecret, err := identityservice.GetOauthSecret("github")
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	redirect_uri := "https://" + request.Host + "/github_callback"
	var oauthUrl = fmt.Sprintf("https://github.com/login/oauth/access_token?&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s",
		clientId, clientSecret, code, redirect_uri)
	var githubUserInfo user.GithubAccount
	httpClient := &http.Client{}
	req, _ := http.NewRequest("POST", oauthUrl, nil)
	req.Header.Add("Accept", "application/json")
	// Get access token from Github
	response, err := httpClient.Do(req)
	if err != nil || response.StatusCode != 200 {
		log.Error(response.Status)
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	githubResponse := struct {
		Access_token      string
		Scope             string
		Token_type        string
		Error             string
		Error_description string
		Error_uri         string
	}{}
	if err := json.NewDecoder(response.Body).Decode(&githubResponse); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if githubResponse.Error != "" {
		log.Error(githubResponse)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Get user info from github
	var apiUrl = fmt.Sprintf("https://api.github.com/user?access_token=%s", githubResponse.Access_token)
	req, _ = http.NewRequest("GET", apiUrl, nil)
	// Get GitHub profile info from this user
	response, err = httpClient.Do(req)

	if err != nil || response.StatusCode != 200 {
		log.Error(response.Status)
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if err := json.NewDecoder(response.Body).Decode(&githubUserInfo); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	userMgr := user.NewManager(request)
	// Save Github user info in db
	var loggedInUser, e = service.GetLoggedInUser(request, w)
	if e != nil {
		log.Error(e)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if err := userMgr.UpdateGithubAccount(loggedInUser, githubUserInfo); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	http.Redirect(w, request, "/", http.StatusTemporaryRedirect)

}
func (service *Service) FacebookCallback(w http.ResponseWriter, request *http.Request) {
	var code = request.URL.Query().Get("code")
	var redirectUri = "https://" + request.Host + "/facebook_callback"
	clientId, err := identityservice.GetOauthClientID("facebook")
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	clientSecret, err := identityservice.GetOauthSecret("facebook")
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	var oauthUrl = fmt.Sprintf("https://graph.facebook.com/v2.6/oauth/access_token?client_id=%s&client_secret=%s&code=%s&redirect_uri=%s",
		clientId, clientSecret, code, redirectUri)
	var fbInfo user.FBInfo
	httpClient := &http.Client{}
	req, _ := http.NewRequest("POST", oauthUrl, nil)
	// Get access token from Github
	response, _ := httpClient.Do(req)
	facebookResponse := struct {
		Access_token string
		Token_type   string
		Expires_in   int
		Error        user.FacebookError
	}{}
	if err := json.NewDecoder(response.Body).Decode(&facebookResponse); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if facebookResponse.Error.Message != "" {
		log.Error(facebookResponse.Error)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	// Get Facebook user info using the Graph API.
	var fields = "id,picture,link,name"
	var apiUrl = fmt.Sprintf("https://graph.facebook.com/v2.6/me/?access_token=%s&fields=%s", facebookResponse.Access_token, fields)
	req, _ = http.NewRequest("GET", apiUrl, nil)
	response, _ = httpClient.Do(req)

	if err := json.NewDecoder(response.Body).Decode(&fbInfo); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	// Save facebook info in database.
	userMgr := user.NewManager(request)
	var loggedInUser, e = service.GetLoggedInUser(request, w)
	if e != nil {
		log.Error(e)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	var fbAccount user.FacebookAccount
	fbAccount.Id = fbInfo.Id
	fbAccount.Name = fbInfo.Name
	fbAccount.Picture = fbInfo.Picture.Data.Url
	fbAccount.Link = fbInfo.Link
	if err := userMgr.UpdateFacebookAccount(loggedInUser, fbAccount); err != nil {
		log.Error(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	http.Redirect(w, request, "/", http.StatusTemporaryRedirect)

}
//ProcessRegistrationForm processes the user registration form
func (service *Service) ProcessRegistrationForm(w http.ResponseWriter, request *http.Request) {
	response := struct {
		Redirecturl string `json:"redirecturl"`
		Error       string `json:"error"`
	}{}
	values := struct {
		TwoFAMethod    string `json:"twofamethod"`
		Login          string `json:"login"`
		Email          string `json:"email"`
		Phonenumber    string `json:"phonenumber"`
		TotpCode       string `json:"totpcode"`
		Password       string `json:"password"`
		RedirectParams string `json:"redirectparams"`
	}{}
	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the registration request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	twoFAMethod := values.TwoFAMethod
	if twoFAMethod != "sms" && twoFAMethod != "totp" {
		log.Info("Invalid 2fa method during registration: ", twoFAMethod)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	totpsession, err := service.GetSession(request, SessionForRegistration, "totp")
	if err != nil {
		log.Error("ERROR while getting the totp registration session", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if totpsession.IsNew {
		log.Debug("New registration session while processing the registration form")
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}
	totpsecret, ok := totpsession.Values["secret"].(string)
	if !ok {
		log.Error("Unable to convert the stored session totp secret to a string")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	valid := user.ValidateUsername(values.Login)
	var phonenumber user.Phonenumber
	if !valid {
		response.Error = "invalid_username_format"
		w.WriteHeader(422)
		json.NewEncoder(w).Encode(response)
		return
	}
	newuser := &user.User{
		Username:       values.Login,
		EmailAddresses: []user.EmailAddress{user.EmailAddress{Label: "main", EmailAddress: values.Email}},
	}
	//validate the username is not taken yet
	userMgr := user.NewManager(request)

	count, err := userMgr.GetPendingRegistrationsCount()
	if err != nil {
		log.Error("Failed to get pending registerations count: ", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	log.Debug("count", count)
	if count >= MAX_PENDING_REGISTRATION_COUNT {
		log.Warn("Maximum amount of pending registrations reached")
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	//we now just depend on mongo unique index to avoid duplicates when concurrent requests are made
	userExists, err := userMgr.Exists(newuser.Username)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if userExists {
		log.Debug("USER ", newuser.Username, " already registered")
		http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict)
		return
	}

	if twoFAMethod == "sms" {
		phonenumber = user.Phonenumber{Label: "main", Phonenumber: values.Phonenumber}
		if !phonenumber.IsValid() {
			log.Debug("Invalid phone number")
			w.WriteHeader(422)
			response.Error = "invalid_phonenumber"
			json.NewEncoder(w).Encode(&response)
			return
		}
		newuser.Phonenumbers = []user.Phonenumber{phonenumber}
		// Remove account after 3 days if it still doesn't have a verified phone by then
		duration := time.Duration(time.Hour * 24 * 3)
		expiresAt := time.Now()
		expiresAt = expiresAt.Add(duration)
		newuser.Expire = db.DateTime(expiresAt)
	} else {
		token := totp.TokenFromSecret(totpsecret)
		if !token.Validate(values.TotpCode) {
			log.Debug("Invalid totp code")
			w.WriteHeader(422)
			response.Error = "invalid_totpcode"
			json.NewEncoder(w).Encode(&response)
			return
		}
	}

	userMgr.Save(newuser)
	passwdMgr := password.NewManager(request)
	err = passwdMgr.Save(newuser.Username, values.Password)
	if err != nil {
		log.Error(err)
		if err.Error() != "internal_error" {
			w.WriteHeader(422)
			response.Error = "invalid_password"
			json.NewEncoder(w).Encode(&response)
		} else {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		}
		return
	}

	if twoFAMethod == "sms" {
		validationkey, err := service.phonenumberValidationService.RequestValidation(request, newuser.Username, phonenumber, fmt.Sprintf("https://%s/phonevalidation", request.Host))
		if err != nil {
			log.Error(err)
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
		registrationSession, err := service.GetSession(request, SessionForRegistration, "registrationdetails")
		registrationSession.Values["username"] = newuser.Username
		registrationSession.Values["phonenumbervalidationkey"] = validationkey
		registrationSession.Values["redirectparams"] = values.RedirectParams

		sessions.Save(request, w)
		response.Redirecturl = fmt.Sprintf("https://%s/register#/smsconfirmation", request.Host)
		json.NewEncoder(w).Encode(&response)
		return
	}

	totpMgr := totp.NewManager(request)
	totpMgr.Save(newuser.Username, totpsecret)
	log.Debugf("Registered %s", newuser.Username)
	service.loginUser(w, request, newuser.Username)
}
//ProcessPhonenumberConfirmationForm processes the Phone number confirmation form
func (service *Service) ProcessPhonenumberConfirmationForm(w http.ResponseWriter, request *http.Request) {
	values := struct {
		Smscode string `json:"smscode"`
	}{}

	response := struct {
		RedirectUrL string `json:"redirecturl"`
		Error       string `json:"error"`
	}{}

	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the ProcessPhonenumberConfirmation request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	registrationSession, err := service.GetSession(request, SessionForRegistration, "registrationdetails")
	if err != nil {
		log.Debug(err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if registrationSession.IsNew {
		sessions.Save(request, w)
		response.RedirectUrL = fmt.Sprintf("https://%s/register/#/smsconfirmation", request.Host)
		json.NewEncoder(w).Encode(&response)
		return
	}

	username, _ := registrationSession.Values["username"].(string)
	validationkey, _ := registrationSession.Values["phonenumbervalidationkey"].(string)

	if isConfirmed, _ := service.phonenumberValidationService.IsConfirmed(request, validationkey); isConfirmed {
		userMgr := user.NewManager(request)
		userMgr.RemoveExpireDate(username)
		service.loginUser(w, request, username)
		return
	}

	smscode := values.Smscode
	if err != nil || smscode == "" {
		log.Debug(err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	err = service.phonenumberValidationService.ConfirmValidation(request, validationkey, smscode)
	if err == validation.ErrInvalidCode {
		w.WriteHeader(422)
		response.Error = "invalid_sms_code"
		json.NewEncoder(w).Encode(&response)
		return
	}
	if err == validation.ErrInvalidOrExpiredKey {
		sessions.Save(request, w)
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		json.NewEncoder(w).Encode(&response)
		return
	} else if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	userMgr := user.NewManager(request)
	userMgr.RemoveExpireDate(username)
	service.loginUser(w, request, username)
}
Example #17
0
//Process2FASMSConfirmation checks the totp 2 factor authentication code
func (service *Service) Process2FASMSConfirmation(w http.ResponseWriter, request *http.Request) {
	username, err := service.getUserLoggingIn(request)
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if username == "" {
		sessions.Save(request, w)
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}
	values := struct {
		Smscode string `json:"smscode"`
	}{}

	if err := json.NewDecoder(request.Body).Decode(&values); err != nil {
		log.Debug("Error decoding the totp confirmation request:", err)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	sessionInfo, err := service.getLoginSessionInformation(request, "")
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	if sessionInfo == nil {
		loginSession, err := service.GetSession(request, SessionLogin, "loginsession")
		if err != nil {
			if err == mgo.ErrNotFound {
				http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
				return
			}
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
		validationkey, _ := loginSession.Values["phonenumbervalidationkey"].(string)
		err = service.phonenumberValidationService.ConfirmValidation(request, validationkey, values.Smscode)
		if err == validation.ErrInvalidCode {
			// TODO: limit to 3 failed attempts
			w.WriteHeader(422)
			log.Debug("invalid code")
			return
		}
	} else if !sessionInfo.Confirmed {
		//Already confirmed on the phone
		validsmscode := (values.Smscode == sessionInfo.SMSCode)

		if !validsmscode {
			// TODO: limit to 3 failed attempts
			w.WriteHeader(422)
			log.Debugf("Expected code %s, got %s", sessionInfo.SMSCode, values.Smscode)
			return
		}
	}
	userMgr := user.NewManager(request)
	userMgr.RemoveExpireDate(username)

	//add last 2fa date if logging in with oauth2
	service.storeLast2FALogin(request, username)

	service.loginUser(w, request, username)
}
// DeleteOrganization is the handler for DELETE /organizations/{globalid}
// Deletes an organization and all data linked to it (join-organization-invitations, oauth_access_tokens, oauth_clients, authorizations)
func (api OrganizationsAPI) DeleteOrganization(w http.ResponseWriter, r *http.Request) {
	globalid := mux.Vars(r)["globalid"]
	orgMgr := organization.NewManager(r)
	logoMgr := organization.NewLogoManager(r)
	if !orgMgr.Exists(globalid) {
		writeErrorResponse(w, http.StatusNotFound, "organization_not_found")
		return
	}
	suborganizations, err := orgMgr.GetSubOrganizations(globalid)
	if handleServerError(w, "fetching suborganizations", err) {
		return
	}
	if len(suborganizations) != 0 {
		writeErrorResponse(w, 422, "organization_has_children")
		return
	}
	err = orgMgr.Remove(globalid)
	if handleServerError(w, "removing organization", err) {
		return
	}
	// Remove the organizations as a member/ an owner of other organizations
	organizations, err := orgMgr.AllByOrg(globalid)
	if handleServerError(w, "fetching organizations where this org is an owner/a member", err) {
		return
	}
	for _, org := range organizations {
		err = orgMgr.RemoveOrganization(org.Globalid, globalid)
		if handleServerError(w, "removing organizations as a member / an owner of another organization", err) {
			return
		}
	}
	if logoMgr.Exists(globalid) {
		err = logoMgr.Remove(globalid)
		if handleServerError(w, "removing organization logo", err) {
			return
		}
	}
	orgReqMgr := invitations.NewInvitationManager(r)
	err = orgReqMgr.RemoveAll(globalid)
	if handleServerError(w, "removing organization invitations", err) {
		return
	}

	oauthMgr := oauthservice.NewManager(r)
	err = oauthMgr.RemoveTokensByGlobalId(globalid)
	if handleServerError(w, "removing organization oauth accesstokens", err) {
		return
	}
	err = oauthMgr.DeleteAllForOrganization(globalid)
	if handleServerError(w, "removing client secrets", err) {
		return
	}
	err = oauthMgr.RemoveClientsById(globalid)
	if handleServerError(w, "removing organization oauth clients", err) {
		return
	}
	userMgr := user.NewManager(r)
	err = userMgr.DeleteAllAuthorizations(globalid)
	if handleServerError(w, "removing all authorizations", err) {
		return
	}
	err = oauthMgr.RemoveClientsById(globalid)
	if handleServerError(w, "removing organization oauth clients", err) {
		return
	}
	l2faMgr := organization.NewLast2FAManager(r)
	err = l2faMgr.RemoveByOrganization(globalid)
	if handleServerError(w, "removing organization 2FA history", err) {
		return
	}
	w.WriteHeader(http.StatusNoContent)
}