예제 #1
0
파일: helper.go 프로젝트: kidstuff/WebAuth
func getUserByIdAndWriteIfError(rw http.ResponseWriter, req *http.Request) (*auth.User, auth.UserManager, error) {
	rw.Header().Set("Content-Type", "application/json; charset=utf-8")

	vars := mux.Vars(req)
	idStr := vars["id"]
	if len(idStr) == 0 {
		response.BadRequestResponse(rw, &response.JSONErr{
			Code:        ErrCodeInvalidId,
			Message:     "Missing 'id' from request",
			Description: "The request URI must be /active/{id}?code=xxxx",
		})
		return nil, nil, errors.New("rest: Missing 'id' from request")
	}

	userMngr, err := auth.Provider().OpenUserMngr(req)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		return nil, nil, err
	}

	u, err := userMngr.FindUser(idStr)
	if err != nil {
		response.ErrorResponse(rw, http.StatusPreconditionFailed, &response.JSONErr{
			Code:    ErrCodeNotExistId,
			Message: "Account not exists",
		})
		return nil, userMngr, err
	}

	return u, userMngr, nil
}
예제 #2
0
/*
GetToken handle both POST and GET method to obtain login token.
Note that only "password" support for "grant_type" right now.

Example Request:
  GET /tokens?grant_type=password&[email protected]&password=xxxxxxxxx
Example Success Response:
  {
    "User": {...}, // auth.User object with empty Pwd, OldPwd, ConfirmCodes
    "ExpiredOn": "2009-11-10T23:00:00Z",
    "AccessToken": "afE.....MNWt-HfVYcFOs7w_ryOzvsYA==" // a secure random base64 encoded string
  }
*/
func GetToken(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-Type", "application/json; charset=utf-8")

	grantType := req.FormValue("grant_type")
	email := req.FormValue("email")
	password := req.FormValue("password")

	// TODO: more detail error message
	if len(grantType) == 0 || len(email) == 0 || len(password) == 0 {
		response.BadRequestResponse(rw, &response.JSONErr{
			Code:        ErrCodeInvalidInput,
			Message:     "Invalid input",
			Description: "grant_type, email and password need to be set.",
		})
		return
	}

	if grantType != "password" {
		response.ErrorResponse(rw, http.StatusNotImplemented, &response.JSONErr{
			Code:        ErrCodeInvalidGrantType,
			Message:     "Invlaid grant_type",
			Description: "Only support grant_type=password",
		})
		return
	}

	userMngr, err := auth.Provider().OpenUserMngr(req)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		return
	}
	defer userMngr.Close()

	user, err := userMngr.ValidateUser(email, password)
	if err != nil {
		response.UnauthorizedResponse(rw, &response.JSONErr{
			Code:        response.ErrCodeNotLogged,
			Message:     err.Error(),
			Description: "Invlaid emaill or password.",
		})
		return
	}

	token, err := userMngr.Login(user.Id, OnlineThreshold)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		return
	}

	// hide sensitive data
	user.Pwd = auth.Password{}
	user.OldPwd = []auth.Password{}
	user.ConfirmCodes = map[string]string{}

	inf := LoginInfo{user, time.Now().Add(OnlineThreshold), token}
	json.NewEncoder(rw).Encode(&inf)
}
예제 #3
0
/*
ActiveAccount handle active request by using confirm code.

Example Request:
  GET /active/some-kind-of-ID?code=secure-random-base64-string
Example Success Response:
  {
    "Message":"Account activated"
  }
*/
func ActiveAccount(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-Type", "application/json; charset=utf-8")

	code := req.FormValue("code")
	if len(code) == 0 {
		response.BadRequestResponse(rw, &response.JSONErr{
			Code:        1.8,
			Message:     "Missing 'code' from request parameter",
			Description: "The request URI must be /active/{id}?code=xxxx",
		})
		return
	}

	u, userMngr, err := getUserByIdAndWriteIfError(rw, req)
	if err != nil {
		return
	}
	defer userMngr.Close()

	if ok := u.ValidConfirmCode("activate", code, false, true); !ok {
		response.ErrorResponse(rw, http.StatusPreconditionFailed, &response.JSONErr{
			Code:    1.8,
			Message: "Invlaid activate code",
		})
		return
	}

	u.Approved = true
	err = userMngr.UpdateUserDetail(u)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{
			Message:     err.Error(),
			Description: "Error when updating user infomation to database.",
		})
		return
	}

	rw.Write([]byte(`{"Message":"Account activated"}`))
}
예제 #4
0
/*
SignUp handle the request for account sign-up. The handler will
check the email and password format. If success it will send an
email and immediately return a 202 status code.

Example Request Body:
  POST /signup
  {
    "Email": "*****@*****.**",
    "Pwd": "xxxxxxxxx",
    "PwdRepeat": "xxxxxxxxx"
  }
Example Success Response:
  {
    "Message":"email sent to [email protected]"
  }
*/
func SignUp(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-Type", "application/json; charset=utf-8")

	userMngr, err := auth.Provider().OpenUserMngr(req)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		return
	}
	defer userMngr.Close()

	credential := struct {
		Email     string
		Pwd       string
		PwdRepeat string
	}{}

	err = json.NewDecoder(req.Body).Decode(&credential)
	if err != nil {
		response.BadRequestResponse(rw, &response.JSONErr{
			Code:        ErrCodeInvalidCredential,
			Message:     err.Error(),
			Description: "Credential must be an valid json object contain Email, Pwd and PwdRepeat.",
		})
		return
	}

	if credential.Pwd != credential.PwdRepeat {
		response.BadRequestResponse(rw, &response.JSONErr{
			Code:    ErrCodePwdMismatch,
			Message: "Pwd and PwdRepeat doesn't match",
		})
		return
	}

	var app bool

	u, err := userMngr.AddUser(credential.Email, credential.PwdRepeat, app)
	if err != nil {
		switch err {
		case auth.ErrInvalidEmail:
			response.ErrorResponse(rw, http.StatusPreconditionFailed, &response.JSONErr{
				Code:    ErrCodeInvalidEmail,
				Message: err.Error(),
			})
		case auth.ErrInvalidPassword:
			response.ErrorResponse(rw, http.StatusPreconditionFailed, &response.JSONErr{
				Code:    ErrCodeInvlaidPwd,
				Message: err.Error(),
			})
		case auth.ErrDuplicateEmail:
			response.ErrorResponse(rw, http.StatusPreconditionFailed, &response.JSONErr{
				Code:    ErrCodeDupEmail,
				Message: err.Error(),
			})
		default:
			response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		}
		return
	}

	conf, err := config.Provider().OpenConfigurator(req)
	if err != nil {
		response.InternalErrorResponse(rw, &response.JSONErr{Message: err.Error()})
		return
	}

	if !app {
		// TODO(!)
		// time out control for mail send
		go func() {
			err = util.SendSimpleMail(conf, u.Email, "Email confirm", u.ConfirmCodes["activate"])
			if err != nil {
				log.Println("rest: SendSimpleMail", err)
			}
			conf.Close()
		}()
	}

	rw.WriteHeader(http.StatusAccepted)
	rw.Write([]byte(`{"Message":"email sent to ` + u.Email + `"}`))
}