Example #1
0
// GetBeginAuthURL gets the URL that the client must visit in order
// to begin the authentication process.
//
// The state argument contains anything you wish to have sent back to your
// callback endpoint.
// The options argument takes any options used to configure the auth request
// sent to the provider. In the case of OAuth2, the options map can contain:
//   1. A "scope" key providing the desired scope(s). It will be merged with the default scope.
func (provider *InstagramProvider) GetBeginAuthURL(state *common.State, options objx.Map) (string, error) {
	if options != nil {
		scope := oauth2.MergeScopes(options.Get(oauth2.OAuth2KeyScope).Str(), instagramDefaultScope)
		provider.config.Set(oauth2.OAuth2KeyScope, scope)
	}
	return oauth2.GetBeginAuthURLWithBase(provider.config.Get(oauth2.OAuth2KeyAuthURL).Str(), state, provider.config)
}
Example #2
0
// HandleAccessRequest takes a *http.Request and a map of input
// parameters, and returns a *AccessRequest representing the request
// for an access token and a *HttpError if any error is encountered.
func (s *Server) HandleAccessRequest(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {
	// Always allow POST.  Only allow GET when the config says it's
	// allowed.
	if request.Method != "POST" && (request.Method != "GET" || !s.Config.AllowGetAccessRequest) {
		return nil, deferror.Get(E_INVALID_REQUEST)
	}

	grantType := AccessRequestType(params.Get("grant_type").Str())
	if s.Config.AllowedAccessTypes.Exists(grantType) {
		switch grantType {
		case AUTHORIZATION_CODE:
			return s.handleAccessRequestAuthorizationCode(request, params)
		case REFRESH_TOKEN:
			return s.handleAccessRequestRefreshToken(request, params)
		case PASSWORD:
			return s.handleAccessRequestPassword(request, params)
		case FB_TOKEN:
			return s.handleAccessRequestFbToken(request, params)
		case CLIENT_CREDENTIALS:
			return s.handleAccessRequestClientCredentials(request, params)
		}
	}

	return nil, deferror.Get(E_UNSUPPORTED_GRANT_TYPE)
}
Example #3
0
// createMapResponse is a helper for generating a response value from
// a value of type map.
func createMapResponse(value reflect.Value, options objx.Map, constructor func(interface{}, interface{}) interface{}, domain string) interface{} {
	response := reflect.MakeMap(value.Type())
	for _, key := range value.MapKeys() {
		var elementOptions objx.Map
		keyStr := key.Interface().(string)
		if options != nil {
			var elementOptionsValue *objx.Value
			if options.Has(keyStr) {
				elementOptionsValue = options.Get(keyStr)
			} else if options.Has("*") {
				elementOptionsValue = options.Get("*")
			}
			if elementOptionsValue.IsMSI() {
				elementOptions = objx.Map(elementOptionsValue.MSI())
			} else if elementOptionsValue.IsObjxMap() {
				elementOptions = elementOptionsValue.ObjxMap()
			} else {
				panic("Don't know what to do with option")
			}
		}
		itemResponse := createResponseValue(value.MapIndex(key), elementOptions, constructor, domain)
		response.SetMapIndex(key, reflect.ValueOf(itemResponse))
	}
	return response.Interface()
}
Example #4
0
// GetBeginAuthURL gets the URL that the client must visit in order
// to begin the authentication process.
//
// The state argument contains anything you wish to have sent back to your
// callback endpoint.
// The options argument takes any options used to configure the auth request
// sent to the provider. In the case of OAuth2, the options map can contain:
//   1. A "scope" key providing the desired scope(s). It will be merged with the default scope.
func (h *HeroProvider) GetBeginAuthURL(state *common.State, options objx.Map) (string, error) {
	if options != nil {
		scope := oauth2.MergeScopes(options.Get(oauth2.OAuth2KeyScope).Str(), h.cfg.DefaultScope)
		h.config.Set(oauth2.OAuth2KeyScope, scope)
	}
	return oauth2.GetBeginAuthURLWithBase(h.config.Get(oauth2.OAuth2KeyAuthURL).Str(), state, h.config)
}
Example #5
0
// ChecClientAuth checks for client_id and client_secret in the
// Authorization header and (if useparams is true) request parameters.
func CheckClientAuth(r *http.Request, params objx.Map, useparams bool) (*BasicAuth, *HttpError) {
	if useparams {
		ret := &BasicAuth{
			Username: params.Get("client_id").Str(),
			Password: params.Get("client_secret").Str(),
		}
		if ret.Username != "" && ret.Password != "" {
			return ret, nil
		}
	}

	return CheckBasicAuth(r)
}
Example #6
0
// createStructResponse is a helper for generating a response value
// from a value of type struct.
func createStructResponse(value reflect.Value, options objx.Map, constructor func(interface{}, interface{}) interface{}, domain string) interface{} {
	structType := value.Type()

	// Support "database/sql".Null* types, and any other types
	// matching that structure
	if v, err := createNullableDbResponse(value, structType); err == nil {
		return v
	}

	response := make(objx.Map)

	for i := 0; i < value.NumField(); i++ {
		fieldType := structType.Field(i)
		fieldValue := value.Field(i)

		if fieldType.Anonymous {
			embeddedResponse := CreateResponse(fieldValue.Interface(), options, constructor, domain).(objx.Map)
			for key, value := range embeddedResponse {
				// Don't overwrite values from the base struct
				if _, ok := response[key]; !ok {
					response[key] = value
				}
			}
		} else if unicode.IsUpper(rune(fieldType.Name[0])) {
			name := ResponseTag(fieldType)
			switch name {
			case "-":
				continue
			default:
				var subOptions objx.Map
				if options != nil && (options.Has(name) || options.Has("*")) {
					var subOptionsValue *objx.Value
					if options.Has(name) {
						subOptionsValue = options.Get(name)
					} else {
						subOptionsValue = options.Get("*")
					}
					if subOptionsValue.IsMSI() {
						subOptions = objx.Map(subOptionsValue.MSI())
					} else if subOptionsValue.IsObjxMap() {
						subOptions = subOptionsValue.ObjxMap()
					} else {
						panic("Don't know what to do with option")
					}
				}
				response[name] = createResponseValue(fieldValue, subOptions, constructor, domain)
			}
		}
	}
	return response
}
Example #7
0
// HandleAuthorizeRequest takes a *Response and an
// objx.Map of parameters, and returns a *AuthorizeRequest
// representing the request present in the *http.Request and
// parameters.
func (s *Server) HandleAuthorizeRequest(params objx.Map) (*AuthorizeRequest, *HttpError) {

	requestType := AuthorizeRequestType(params.Get("response_type").Str())
	if s.Config.AllowedAuthorizeTypes.Exists(requestType) {
		switch requestType {
		case CODE:
			return s.handleAuthorizeRequestCode(params)
		case TOKEN:
			return s.handleAuthorizeRequestToken(params)
		}
	}

	return nil, deferror.Get(E_UNSUPPORTED_RESPONSE_TYPE)
}
Example #8
0
func (s *Server) FinishAccessRequest(params objx.Map, ar *AccessRequest, target AccessData) (response objx.Map, httpErr *HttpError) {
	if ar.Authorized {
		target.SetClient(ar.Client)
		target.SetAuthorizeData(ar.AuthorizeData)
		target.SetAccessData(ar.AccessData)
		target.SetRedirectUri(params.Get("redirect_uri").Str())
		target.SetCreatedAt(time.Now())
		target.SetExpiresIn(ar.Expiration)

		accessToken, refreshToken, tokenErr := s.AccessTokenGen.GenerateAccessToken(ar.GenerateRefresh)
		if tokenErr != nil {
			return nil, tokenErr
		}
		target.SetAccessToken(accessToken)
		target.SetRefreshToken(refreshToken)

		if err := s.Storage.SaveAccess(target); err != nil {
			if httpErr, ok := err.(*HttpError); ok {
				return nil, httpErr
			} else {
				return nil, deferror.Get(err.Error())
			}
		}

		if target.GetAuthorizeData() != nil {
			s.Storage.RemoveAuthorize(target.GetAuthorizeData().GetCode())
		}

		if target.GetAccessData() != nil {
			if target.GetAccessData().GetRefreshToken() != "" {
				s.Storage.RemoveRefresh(target.GetAccessData().GetRefreshToken())
			}
			s.Storage.RemoveAccess(target.GetAccessData().GetAccessToken())
		}

		response := objx.Map{
			"access_token": target.GetAccessToken(),
			"token_type":   s.Config.TokenType,
			"expires_in":   target.GetExpiresIn(),
		}
		if target.GetRefreshToken() != "" {
			response.Set("refresh_token", target.GetRefreshToken())
		}
		if ar.Scope != "" {
			response.Set("scope", ar.Scope)
		}
		return response, nil
	}
	return nil, deferror.Get(E_ACCESS_DENIED)
}
Example #9
0
func (s *Server) handleAccessRequestFbToken(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {
	ret := &AccessRequest{
		Type:            FB_TOKEN,
		Scope:           params.Get("scope").Str(),
		GenerateRefresh: true,
		Expiration:      s.Config.AccessExpiration,
	}

	var err *HttpError
	if ret.Client, err = s.GetValidClient(params.Get("client_id").Str()); err != nil {
		return nil, err
	}
	ret.RedirectUri = ret.Client.GetRedirectUri()
	return ret, nil
}
Example #10
0
func (s *Server) handleAccessRequestAuthorizationCode(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {
	auth, err := GetValidAuth(request, params, s.Config.AllowClientSecretInParams)
	if err != nil {
		return nil, err
	}

	ret := &AccessRequest{
		Type:            AUTHORIZATION_CODE,
		Code:            params.Get("code").Str(),
		RedirectUri:     params.Get("redirect_uri").Str(),
		GenerateRefresh: true,
		Expiration:      s.Config.AccessExpiration,
	}

	if ret.Code == "" {
		return nil, deferror.Get(E_INVALID_GRANT)
	}

	ret.Client, err = s.GetValidClientWithSecret(auth.Username, auth.Password)
	if err != nil {
		return nil, err
	}

	ret.AuthorizeData, err = s.GetValidAuthData(ret.Code)
	if err != nil {
		return nil, err
	}

	if ret.AuthorizeData.GetClient().GetId() != ret.Client.GetId() {
		return nil, deferror.Get(E_INVALID_GRANT)
	}

	if ret.RedirectUri == "" {
		ret.RedirectUri = ret.Client.GetRedirectUri()
	}
	if err = ValidateUri(ret.Client.GetRedirectUri(), ret.RedirectUri); err != nil {
		return nil, err
	}
	if ret.AuthorizeData.GetRedirectUri() != ret.RedirectUri {
		return nil, deferror.Get(E_INVALID_REQUEST)
	}

	ret.Scope = ret.AuthorizeData.GetScope()
	return ret, nil
}
Example #11
0
func (s *Server) handleAuthorizeRequestToken(params objx.Map) (*AuthorizeRequest, *HttpError) {
	ret := &AuthorizeRequest{
		Type:        TOKEN,
		State:       params.Get("state").Str(),
		Scope:       params.Get("scope").Str(),
		RedirectUri: params.Get("redirect_uri").Str(),
		Authorized:  false,
		// this type will generate a token directly, use access token expiration instead.
		Expiration: s.Config.AccessExpiration,
	}

	var err *HttpError

	ret.Client, err = s.GetValidClient(params.Get("client_id").Str())
	if err != nil {
		return nil, err
	}

	if ret.RedirectUri == "" {
		ret.RedirectUri = ret.Client.GetRedirectUri()
	}
	if err = ValidateUri(ret.Client.GetRedirectUri(), ret.RedirectUri); err != nil {
		return nil, err
	}

	return ret, nil
}
Example #12
0
func (s *Server) handleAuthorizeRequestCode(params objx.Map) (*AuthorizeRequest, *HttpError) {
	ret := &AuthorizeRequest{
		Type:        CODE,
		State:       params.Get("state").Str(),
		Scope:       params.Get("scope").Str(),
		RedirectUri: params.Get("redirect_uri").Str(),
		Authorized:  false,
		Expiration:  s.Config.AuthorizationExpiration,
	}

	var err *HttpError

	ret.Client, err = s.GetValidClient(params.Get("client_id").Str())
	if err != nil {
		return nil, err
	}

	if ret.RedirectUri == "" {
		ret.RedirectUri = ret.Client.GetRedirectUri()
	}
	if err = ValidateUri(ret.Client.GetRedirectUri(), ret.RedirectUri); err != nil {
		return nil, err
	}

	return ret, nil
}
Example #13
0
func (s *Server) handleAccessRequestRefreshToken(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {
	ret := &AccessRequest{
		Type:            REFRESH_TOKEN,
		Code:            params.Get("refresh_token").Str(),
		Scope:           params.Get("scope").Str(),
		GenerateRefresh: true,
		Expiration:      s.Config.AccessExpiration,
	}

	if ret.Code == "" {
		return nil, deferror.Get(E_INVALID_GRANT)
	}

	var err *HttpError
	ret.Client, err = s.GetValidClient(params.Get("client_id").Str())
	if err != nil {
		return nil, err
	}

	ret.AccessData, err = s.GetValidRefresh(ret.Code)
	if err != nil {
		return nil, err
	}

	if ret.AccessData.GetClient().GetId() != ret.Client.GetId() {
		return nil, deferror.Get(E_INVALID_CLIENT)
	}

	ret.RedirectUri = ret.AccessData.GetRedirectUri()
	if ret.Scope == "" {
		ret.Scope = ret.AccessData.GetScope()
	}

	return ret, nil
}
Example #14
0
// createResponseValue is a helper for generating a response value for
// a single value in a response object.
func createResponseValue(value reflect.Value, options objx.Map, constructor func(interface{}, interface{}) interface{}, domain string) (responseValue interface{}) {
	if value.Kind() == reflect.Ptr && !value.Elem().IsValid() {
		responseValue = nil
		if nilResponder, ok := value.Interface().(NilResponder); ok {
			responseValue = nilResponder.NilResponseValue()
		}
	} else if options.Get("type").Str() != "full" {
		switch source := value.Interface().(type) {
		case ResponseValueCreator:
			responseValue = createResponse(source.ResponseValue(options), true, options, constructor, domain)
		case fmt.Stringer:
			responseValue = createResponse(source.String(), true, options, constructor, domain)
		case error:
			responseValue = createResponse(source.Error(), true, options, constructor, domain)
		default:
			responseValue = createResponse(value.Interface(), true, options, constructor, domain)
		}
	} else {
		responseValue = createResponse(value.Interface(), true, options, constructor, domain)
	}
	return
}
Example #15
0
func (s *Server) handleAccessRequestClientCredentials(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {
	auth, err := GetValidAuth(request, params, s.Config.AllowClientSecretInParams)
	if err != nil {
		return nil, err
	}

	ret := &AccessRequest{
		Type:            CLIENT_CREDENTIALS,
		Scope:           params.Get("scope").Str(),
		GenerateRefresh: true,
		Expiration:      s.Config.AccessExpiration,
	}

	ret.Client, err = s.GetValidClientWithSecret(auth.Username, auth.Password)
	if err != nil {
		return nil, err
	}

	ret.RedirectUri = ret.Client.GetRedirectUri()

	return ret, nil
}
Example #16
0
// handleAccessRequestPassword handles access requests that POST a
// username and password directly to the token end point.  This is
// usually a call from a client-side application or script, so we
// don't require a client secret, because it probably can't be secured
// properly, anyway.
func (s *Server) handleAccessRequestPassword(request *http.Request, params objx.Map) (*AccessRequest, *HttpError) {

	ret := &AccessRequest{
		Type:            PASSWORD,
		Username:        params.Get("username").Str(),
		Password:        params.Get("password").Str(),
		Scope:           params.Get("scope").Str(),
		GenerateRefresh: true,
		Expiration:      s.Config.AccessExpiration,
	}

	if ret.Username == "" || ret.Password == "" {
		return nil, deferror.Get(E_INVALID_GRANT)
	}

	var err *HttpError
	ret.Client, err = s.GetValidClient(params.Get("client_id").Str())
	if err != nil {
		return nil, err
	}
	ret.RedirectUri = ret.Client.GetRedirectUri()
	return ret, nil
}
Example #17
0
// CompleteAuth takes a map of arguments that are used to
// complete the authorisation process, completes it, and returns
// the appropriate common.Credentials.
//
// The data must contain an OAuth2KeyCode obtained from the auth
// server.
func CompleteAuth(tripperFactory common.TripperFactory, data objx.Map, config *common.Config, provider common.Provider) (*common.Credentials, error) {

	// get the code
	codeList := data.Get(OAuth2KeyCode).Data()

	code, ok := codeList.(string)
	if !ok {

		if codeList == nil || len(codeList.([]string)) == 0 {
			return nil, &common.MissingParameterError{ParameterName: OAuth2KeyCode}
		}
		code = codeList.([]string)[0]
		if len(code) == 0 {
			return nil, &common.MissingParameterError{ParameterName: OAuth2KeyCode}
		}
	}

	client, clientErr := GetClient(tripperFactory, common.EmptyCredentials, provider)
	if clientErr != nil {
		return nil, clientErr
	}

	params := objx.MSI(OAuth2KeyGrantType, OAuth2GrantTypeAuthorizationCode,
		OAuth2KeyRedirectUrl, config.Get(OAuth2KeyRedirectUrl).Str(),
		OAuth2KeyScope, config.Get(OAuth2KeyScope).Str(),
		OAuth2KeyCode, code,
		OAuth2KeyClientID, config.Get(OAuth2KeyClientID).Str(),
		OAuth2KeySecret, config.Get(OAuth2KeySecret).Str())

	// post the form
	response, requestErr := client.PostForm(config.Get(OAuth2KeyTokenURL).Str(), params.URLValues())

	if requestErr != nil {
		return nil, requestErr
	}

	// make sure we close the body
	defer func() {
		if response.Body != nil {
			response.Body.Close()
		}
	}()

	// make sure we have an OK response
	if response.StatusCode != http.StatusOK {
		return nil, &common.AuthServerError{
			ErrorMessage: fmt.Sprintf("Server replied with %s.", response.Status),
			Response:     response,
		}
	}

	content, _, mimeTypeErr := mime.ParseMediaType(response.Header.Get("Content-Type"))

	if mimeTypeErr != nil {
		return nil, mimeTypeErr
	}

	// prepare the credentials object
	creds := &common.Credentials{Map: objx.MSI()}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	switch content {
	case "application/x-www-form-urlencoded", "text/plain":

		vals, err := objx.FromURLQuery(string(body))
		if err != nil {
			return nil, err
		}

		// did an error occur?
		if len(vals.Get("error").Str()) > 0 {
			return nil, &common.AuthServerError{
				ErrorMessage: vals.Get("error").Str(),
				Response:     response,
			}
		}

		expiresIn, _ := time.ParseDuration(vals.Get(OAuth2KeyExpiresIn).Str() + "s")

		creds.Set(OAuth2KeyAccessToken, vals.Get(OAuth2KeyAccessToken).Str())
		creds.Set(OAuth2KeyRefreshToken, vals.Get(OAuth2KeyRefreshToken).Str())
		creds.Set(OAuth2KeyExpiresIn, expiresIn)

	default: // use JSON

		var data objx.Map

		jsonErr := json.Unmarshal(body, &data)

		if jsonErr != nil {
			return nil, jsonErr
		}

		// handle the time
		timeDuration := data.Get(OAuth2KeyExpiresIn).Float64()
		data.Set(OAuth2KeyExpiresIn, time.Duration(timeDuration)*time.Second)

		// merge this data into the creds
		creds.MergeHere(data)

	}

	return creds, nil
}
Example #18
0
func (engine *RuleEngine) DefineVirtualDevice(name string, obj objx.Map) error {
	title := name
	if obj.Has("title") {
		title = obj.Get("title").Str(name)
	}

	// if the device was for some reason defined in another script,
	// we must remove it
	engine.model.RemoveLocalDevice(name)

	dev := engine.model.EnsureLocalDevice(name, title)
	engine.cleanup.AddCleanup(func() {
		// runs when the rule file is reloaded
		engine.model.RemoveLocalDevice(name)
	})

	if !obj.Has("cells") {
		return nil
	}

	v := obj.Get("cells")
	var m objx.Map
	switch {
	case v.IsObjxMap():
		m = v.ObjxMap()
	case v.IsMSI():
		m = objx.Map(v.MSI())
	default:
		return fmt.Errorf("device %s doesn't have proper 'cells' property", name)
	}

	// Sorting cells by their names is not important when defining device
	// while the engine is not active because all the cells will be published
	// all at once when the engine starts.
	// On the other hand, when defining the device for the active engine
	// the newly added cells are published immediately and if their order
	// changes (map key order is random) the tests may break.
	cellNames := make([]string, 0, len(m))
	for cellName, _ := range m {
		cellNames = append(cellNames, cellName)
	}
	sort.Strings(cellNames)

	for _, cellName := range cellNames {
		maybeCellDef := m[cellName]
		cellDef, ok := maybeCellDef.(objx.Map)
		if !ok {
			cd, ok := maybeCellDef.(map[string]interface{})
			if !ok {
				return fmt.Errorf("%s/%s: bad cell definition", name, cellName)
			}
			cellDef = objx.Map(cd)
		}
		cellType, ok := cellDef["type"]
		if !ok {
			return fmt.Errorf("%s/%s: no cell type", name, cellName)
		}
		// FIXME: too much spaghetti for my taste
		if cellType == "pushbutton" {
			dev.SetButtonCell(cellName)
			continue
		}

		cellValue, ok := cellDef["value"]
		if !ok {
			return fmt.Errorf("%s/%s: cell value required for cell type %s",
				name, cellName, cellType)
		}

		cellReadonly := false
		cellReadonlyRaw, hasReadonly := cellDef["readonly"]

		if hasReadonly {
			cellReadonly, ok = cellReadonlyRaw.(bool)
			if !ok {
				return fmt.Errorf("%s/%s: non-boolean value of readonly property",
					name, cellName)
			}
		}

		if cellType == "range" {
			fmax := DEFAULT_CELL_MAX
			max, ok := cellDef["max"]
			if ok {
				fmax, ok = max.(float64)
				if !ok {
					return fmt.Errorf("%s/%s: non-numeric value of max property",
						name, cellName)
				}
			}
			// FIXME: can be float
			dev.SetRangeCell(cellName, cellValue, fmax, cellReadonly)
		} else {
			dev.SetCell(cellName, cellType.(string), cellValue, cellReadonly)
		}
	}

	return nil
}