Example #1
0
File: manager.go Project: gourd/kit
func (m *Manager) showLoginForm(lctx *LoginFormContext, w http.ResponseWriter, r *http.Request) {

	logger := msg
	logger.Log(
		"func", "showLoginForm (Manager.GetEndpoints)")

	// build action query
	ar := getOsinAuthRequest(lctx.Context) // presume the context has *osin.AuthorizeRequest
	aq := url.Values{}
	aq.Add("response_type", string(ar.Type))
	aq.Add("client_id", ar.Client.GetId())
	aq.Add("state", ar.State)
	aq.Add("scope", ar.Scope)
	aq.Add("redirect_uri", ar.RedirectUri)

	// form action url
	aurl := r.URL
	aurl.RawQuery = aq.Encode()

	logger.Log(
		"func", "showLoginForm (Manager.GetEndpoints)",
		"action url", aurl)

	lctx.ActionURL = aurl

	w.Header().Add("Content-Type", "text/html;charset=utf8")
	if err := m.loginFormFunc(lctx); err != nil {
		serr := store.ExpandError(err)
		logger.Log(
			"func", "showLoginForm (Manager.GetEndpoints)",
			"action url", aurl,
			"error", serr.ServerMsg)
	}
}
Example #2
0
// NewUserFunc creates the default parser of login HTTP request
func NewUserFunc(idName string) UserFunc {
	return func(r *http.Request, us store.Store) (ou OAuth2User, err error) {

		var c store.Conds

		id := r.Form.Get(idName)

		if id == "" {
			serr := store.Error(http.StatusBadRequest, "empty user identifier")
			err = serr
			return
		}

		// different condition based on the user_id field format
		if govalidator.IsEmail(id) {
			c = store.NewConds().Add("email", id)
		} else {
			c = store.NewConds().Add("username", id)
		}

		// get user from database
		u := us.AllocEntity()
		err = us.One(c, u)

		if err != nil {
			serr := store.ExpandError(err)
			if serr.Status != http.StatusNotFound {
				serr.TellServer("Error searching user %#v: %s", id, serr.ServerMsg)
				return
			}
			err = serr
			return
		}

		// if user does not exists
		if u == nil {
			serr := store.Error(http.StatusBadRequest, "Username or Password incorrect")
			serr.TellServer("Unknown user %#v attempt to login", id)
			err = serr
			return
		}

		// cast the user as OAuth2User
		// and do password check
		ou, ok := u.(OAuth2User)
		if !ok {
			serr := store.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
			serr.TellServer("User cannot be cast as OAuth2User")
			err = serr
			return
		}

		return
	}
}
Example #3
0
File: service.go Project: gourd/kit
// jsonErrorEncoder expands given error to StoreError then encode to JSON
func jsonErrorEncoder(ctx context.Context, err error, w http.ResponseWriter) {
	w.Header().Add("Content-Type", "application/json")

	// quick fix for gokit bad request wrapping problem
	switch err.(type) {
	case httptransport.Error:
		err = err.(httptransport.Error).Err
	}

	serr := store.ExpandError(err)
	log.Printf("error: %#v", serr.ServerMsg)
	json.NewEncoder(w).Encode(serr)
}
Example #4
0
File: storage.go Project: gourd/kit
// GetClient implements osin.Storage.GetClient
func (storage *Storage) GetClient(id string) (c osin.Client, err error) {

	// TODO: use logger := log.NewContext(,sg)
	logger, errLogger := msg, errMsg
	logger.Log(
		"method", "GetClient",
		"id", id)

	srv, err := store.Get(storage.ctx, KeyClient)
	if err != nil {
		serr := store.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
		serr.TellServer("unable to get client store: %s", err)
		err = serr
		return
	}
	defer srv.Close()

	e := &Client{}
	conds := store.NewConds()
	conds.Add("id", id)

	err = srv.One(conds, e)
	if err != nil {
		serr := store.ExpandError(err)
		errLogger.Log(
			"method", "GetClient",
			"id", id,
			"cond", conds,
			"message", "Failed running One()",
			"error", serr.ServerMsg)
		return
	} else if e == nil {
		errLogger.Log(
			"method", "GetClient",
			"id", id,
			"cond", fmt.Sprintf("%#v", conds),
			"message", "Client not found")
		err = store.Error(http.StatusNotFound,
			"Client not found for the given id")
		return
	}

	c = e
	return
}
Example #5
0
func TestParseError_User(t *testing.T) {

	var code int
	var msg string
	userMsg := "Some user error"

	var err error = errors.New(userMsg)
	code, msg = store.ParseError(err)

	if code != http.StatusInternalServerError {
		t.Errorf("Incorrect status code. Expecting %d but get %d",
			http.StatusInternalServerError, code)
	}
	if msg != userMsg {
		t.Errorf("Incorrect status message. Expecting %s but get %s",
			userMsg, msg)
	}

	serr := store.ExpandError(err)
	if serr.Status != http.StatusInternalServerError {
		t.Errorf("Incorrect StoreError.Status. Expecting %#v but get %#v",
			http.StatusInternalServerError, serr.Status)
	}
	if serr.Code != http.StatusInternalServerError {
		t.Errorf("Incorrect StoreError.Code. Expecting %#v but get %#v",
			http.StatusInternalServerError, serr.Code)
	}
	if serr.ServerMsg != userMsg {
		t.Errorf("Incorrect StoreError.ServerMsg. Expecting %#v but get %#v",
			userMsg, serr.ServerMsg)
	}
	if serr.ClientMsg != userMsg {
		t.Errorf("Incorrect StoreError.ClientMsg. Expecting %#v but get %#v",
			userMsg, serr.ClientMsg)
	}
	if serr.DeveloperMsg != "" {
		t.Errorf("Incorrect StoreError.DeveloperMsg. Expecting %#v but get %#v",
			"", serr.DeveloperMsg)
	}

}
Example #6
0
func TestParseError_Singletons(t *testing.T) {

	var code int
	var msg string

	var err error = store.ErrorNotFound
	msgExpect := err.Error()

	code, msg = store.ParseError(err)
	if code != http.StatusNotFound {
		t.Errorf("Incorrect status code. Expecting %d but get %d",
			http.StatusNotFound, code)
	}
	if msg != msgExpect {
		t.Errorf("Incorrect status message. Expecting %s but get %s",
			msgExpect, msg)
	}

	serr := store.ExpandError(err)
	if serr.Status != http.StatusNotFound {
		t.Errorf("Incorrect StoreError.Status. Expecting %#v but get %#v",
			http.StatusNotFound, serr.Status)
	}
	if serr.Code != http.StatusNotFound {
		t.Errorf("Incorrect StoreError.Code. Expecting %#v but get %#v",
			http.StatusNotFound, serr.Code)
	}
	if serr.ServerMsg != msgExpect {
		t.Errorf("Incorrect StoreError.ServerMsg. Expecting %#v but get %#v",
			msgExpect, serr.ServerMsg)
	}
	if serr.ClientMsg != msgExpect {
		t.Errorf("Incorrect StoreError.ClientMsg. Expecting %#v but get %#v",
			msgExpect, serr.ClientMsg)
	}
	if serr.DeveloperMsg != "" {
		t.Errorf("Incorrect StoreError.DeveloperMsg. Expecting %#v but get %#v",
			"", serr.DeveloperMsg)
	}

}
Example #7
0
// NewLoginFormFunc creates a LoginFormFunc from given template
func NewLoginFormFunc(idName, tpl string) LoginFormFunc {

	// compile template for login form
	loginTpl, err := template.New("loginForm").Parse(tpl)
	if err != nil {
		panic(err) // should not happen, simply panic
	}

	return func(lctx *LoginFormContext) (err error) {

		// TODO: pass the login error into showLoginForm context
		//       and display it to the visitor

		// template variables
		vars := map[string]interface{}{
			"Title":        "Login",
			"FormAction":   lctx.ActionURL,
			"UserID":       "",
			"TextUserID":   "Login ID or Email",
			"TextPassword": "******",
			"TextSubmit":   "Login",
		}

		if lctx.Request.Method == "POST" && lctx.LoginErr != nil {
			vars["LoginErr"] = lctx.LoginErr.Error()
			vars["UserID"] = lctx.Request.Form.Get(idName)
		}

		// render the form with vars
		err = loginTpl.Execute(lctx.ResponseWriter, vars)
		if err != nil {
			serr := store.ExpandError(err)
			serr.TellServer("error executing login template: %#v", err.Error())
			err = serr
			return
		}

		return
	}
}
Example #8
0
func TestError(t *testing.T) {
	estatus, ecode, emsg := testErrorCode()
	var err error = store.Error(ecode, emsg)
	code, msg := store.ParseError(err)

	if code != ecode {
		t.Errorf("code output not correct. Expect %#v but get %#v",
			ecode, code)
	}
	if msg != emsg {
		t.Errorf("msg output not correct. Expect %#v but get %#v",
			emsg, msg)
	}

	serr := store.ExpandError(err)
	if serr.Status != estatus {
		t.Errorf("Incorrect StoreError.Status. Expecting %#v but get %#v",
			estatus, serr.Status)
	}
	if serr.Code != ecode {
		t.Errorf("Incorrect StoreError.Code. Expecting %#v but get %#v",
			ecode, serr.Code)
	}
	if serr.ServerMsg != emsg {
		t.Errorf("Incorrect StoreError.ServerMsg. Expecting %#v but get %#v",
			emsg, serr.ServerMsg)
	}
	if serr.ClientMsg != emsg {
		t.Errorf("Incorrect StoreError.ClientMsg. Expecting %#v but get %#v",
			emsg, serr.ClientMsg)
	}
	if serr.DeveloperMsg != "" {
		t.Errorf("Incorrect StoreError.DeveloperMsg. Expecting %#v but get %#v",
			"", serr.DeveloperMsg)
	}

}
Example #9
0
File: manager.go Project: gourd/kit
// GetEndpoints generate endpoints http handers and return
func (m *Manager) GetEndpoints(factory store.Factory) *Endpoints {

	// try to login with given request login
	tryLogin := func(ctx context.Context, r *http.Request) (user OAuth2User, err error) {

		logger := msg
		logger.Log(
			"func", "tryLogin (Manager.GetEndpoints)")

		// parse POST input
		r.ParseForm()
		if r.Method == "POST" {

			var u OAuth2User
			var us store.Store

			// get and check password non-empty
			password := r.Form.Get("password")
			if password == "" {
				err = errors.New("empty password")
				return
			}

			// obtain user store
			us, err = store.Get(ctx, KeyUser)
			if err != nil {
				err = store.Error(
					http.StatusInternalServerError,
					http.StatusText(http.StatusInternalServerError)).
					TellServer("error obtaining user store: %s", err.Error())
				return
			}

			// get user by userFunc
			u, err = m.userFunc(r, us)
			if err != nil {
				serr := store.ExpandError(err)
				if serr.Status == http.StatusNotFound {
					err = store.Error(http.StatusBadRequest, "user id or password incorrect").
						TellServer("user not found")
				} else {
					err = store.Error(
						http.StatusInternalServerError,
						http.StatusText(http.StatusInternalServerError)).
						TellServer("error obtaining user: %s", serr.ServerMsg)
				}
				return
			}

			// if user is nil, user not found
			if u == nil {
				err = store.Error(http.StatusBadRequest, "user not found")
				return
			}

			// if password does not match
			if !u.PasswordIs(password) {
				err = store.Error(http.StatusBadRequest, "user id or password incorrect").
					TellServer("incorrect password")
				return
			}

			// return pointer of user object, allow it to be re-cast
			logger.Log(
				"func", "tryLogin (Manager.GetEndpoints)",
				"message", "login success")
			user = u
			return
		}

		// no POST input or incorrect login, show form
		// end login handling sequence and wait for
		// user input from login form
		err = store.Error(http.StatusUnauthorized, "Require login").
			TellServer("no POST input")
		return
	}

	type ContextHandlerFunc func(ctx context.Context,
		w http.ResponseWriter, r *http.Request) *osin.Response

	// sessionContext takes a ContextHandlerFunc and returns
	// a http.HandlerFunc
	sessionContext := func(inner ContextHandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			// per connection based context.Context, with factory
			ctx := store.WithFactory(context.Background(), factory)
			defer store.CloseAllIn(ctx)
			if resp := inner(ctx, w, r); resp != nil {
				if resp.InternalError != nil {
					errLogger := errMsg
					errLogger.Log(
						"func", "sessionContext (Manager.GetEndpoints)",
						"error", resp.InternalError.Error())
				}
				osin.OutputJSON(resp, w, r)
			}
		}
	}

	ep := Endpoints{}

	// authorize endpoint
	ep.Auth = sessionContext(func(ctx context.Context,
		w http.ResponseWriter, r *http.Request) *osin.Response {

		logger := msg
		logger.Log(
			"endpoint", "auth")

		srvr := m.osinServer
		resp := srvr.NewResponse()
		resp.Storage.(*Storage).SetContext(ctx)

		// handle authorize request with osin
		if ar := srvr.HandleAuthorizeRequest(resp, r); ar != nil {
			logger.Log(
				"endpoint", "auth",
				"message", "handle authorize request")

			// TODO: maybe redirect to another URL for
			//       dedicated login form flow?
			var err error
			if ar.UserData, err = tryLogin(ctx, r); err != nil {
				serr := store.ExpandError(err)
				logger.Log(
					"endpoint", "auth",
					"message", "handle authorize request",
					"error", serr.ServerMsg)

				lctx := &LoginFormContext{
					Context:        withOsinAuthRequest(ctx, ar),
					LoginErr:       err,
					ResponseWriter: w,
					Request:        r,
					Logger:         logger,
				}
				m.showLoginForm(lctx, w, r)
				return nil
			}

			logger.Log(
				"endpoint", "auth",
				"message", "User obtained",
				"osin.AuthorizeData.UserData", fmt.Sprintf("%#v", ar.UserData))

			ar.Authorized = true
			srvr.FinishAuthorizeRequest(resp, r, ar)
		}

		logger.Log(
			"endpoint", "auth",
			"message", "User obtained",
			"response", fmt.Sprintf("%#v", resp))

		return resp
	})

	// token endpoint
	ep.Token = sessionContext(func(ctx context.Context,
		w http.ResponseWriter, r *http.Request) *osin.Response {

		logger := msg
		logger.Log(
			"endpoint", "token")

		srvr := m.osinServer
		resp := srvr.NewResponse()
		resp.Storage.(*Storage).SetContext(ctx)

		if ar := srvr.HandleAccessRequest(resp, r); ar != nil {
			// TODO: handle authorization
			// check if the user has the permission to grant the scope
			logger.Log(
				"endpoint", "token",
				"message", "access successful")
			ar.Authorized = true
			srvr.FinishAccessRequest(resp, r, ar)
		}

		logger.Log(
			"endpoint", "token",
			"response", fmt.Sprintf("%#v", resp))
		return resp
	})

	// information endpoint
	ep.Info = sessionContext(func(ctx context.Context,
		w http.ResponseWriter, r *http.Request) *osin.Response {

		logger := msg
		logger.Log(
			"endpoint", "information")

		srvr := m.osinServer

		resp := srvr.NewResponse()
		resp.Storage.(*Storage).SetContext(ctx)
		defer resp.Close()

		if ir := srvr.HandleInfoRequest(resp, r); ir != nil {
			srvr.FinishInfoRequest(resp, r, ir)
		}

		logger.Log(
			"endpoint", "information",
			"response", fmt.Sprintf("%#v", resp))
		return resp
	})

	return &ep

}
Example #10
0
File: storage.go Project: gourd/kit
// SaveAccess writes AccessData.
// If RefreshToken is not blank, it must save in a way that can be loaded using LoadRefresh.
func (storage *Storage) SaveAccess(ad *osin.AccessData) (err error) {

	// TODO: use logger := log.NewContext(,sg)
	logger, errLogger := msg, errMsg
	logger.Log(
		"method", "SaveAccess",
		"*osin.AccessData", ad)

	srv, err := store.Get(storage.ctx, KeyAccess)
	if err != nil {
		return
	}
	defer srv.Close()

	// generate database access type
	e := &AccessData{}
	err = e.ReadOsin(ad)
	if err != nil {
		return
	}

	// store client id with access in database
	e.ClientID = e.Client.GetId()

	// if AuthorizeData is set, store as JSON
	if ad.AuthorizeData != nil {
		var b []byte
		authData := &AuthorizeData{}
		if err = authData.ReadOsin(ad.AuthorizeData); err != nil {
			return
		}
		if b, err = json.Marshal(authData); err != nil {
			return
		}
		e.AuthorizeDataJSON = string(b)
	}

	// if AccessData is set, store as JSON
	if ad.AccessData != nil {
		var b []byte
		accessData := &AccessData{}
		if err = accessData.ReadOsin(ad.AccessData); err != nil {
			return
		}
		if accessData.AccessData != nil {
			// forget data of too long ago
			accessData.AccessData = nil
		}
		if b, err = json.Marshal(accessData); err != nil {
			return
		}
		e.AccessDataJSON = string(b)
	}

	// create in database
	if err = srv.Create(store.NewConds(), e); err != nil {
		serr := store.ExpandError(err)
		errLogger.Log(
			"method", "SaveAccess",
			"*osin.AccessData", ad,
			"err", serr.ServerMsg)
	}
	return
}