Oathkeeper在反向代理模式下的重要功能及调用流程

0  初始化

          首先,设置Oathkeeper在cmd\server\server.go中,设置反向代理的两个重要执行函数:

    handler := &httputil.ReverseProxy{
			Director:  proxy.Director,//通过proxy.Director完成对HTTP请求的认证等操作
			Transport: proxy,//通过的proxy.RoundTrip完成与后端服务的通信
		}

         具体调用流程如下:

         step1:当收到HTTP请求时,调用httputil.ReverseProxy.ServeHTTP对HTTP请求进行处理;

         step2:调用proxy.Director,依据HTTP数据包的信息对HTTP请求进行认证、授权。

         step3:调用proxy.RoundTrip,如果认证、授权阶段没有错误,则将HTTP请求发送给后端;否则,向客户端发送错误信息。

1  认证、鉴权及更改

         这部分的实现代码如下所示,先后对该HTTP请求进行认证、授权:

/*
    根据匹配到的规则,对HTTP请求进行认证、授权以及更改
*/
func (d *RequestHandler) HandleRequest(r *http.Request, rl *rule.Rule) (session *authn.AuthenticationSession, err error) {
	var found bool

	fields := map[string]interface{}{
		"http_method":     r.Method,
		"http_url":        r.URL.String(),
		"http_host":       r.Host,
		"http_user_agent": r.UserAgent(),
		"rule_id":         rl.ID,
	}


	session = d.InitializeAuthnSession(r, rl)
    //看一下这个规则是否有对应的认证器,不能没有
	if len(rl.Authenticators) == 0 {
		err = errors.New("No authentication handler was set in the rule")
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("reason_id", "authentication_handler_missing").
			Warn("No authentication handler was set in the rule")
		return nil, err
	}

	//Authenticator-->认证者
	for _, a := range rl.Authenticators {
        //看一下Oathkeeper是否支持该认证器
		anh, err := d.r.PipelineAuthenticator(a.Handler)
		if err != nil {
			d.r.Logger().WithError(err).
				WithFields(fields).
				WithField("granted", false).
				WithField("authentication_handler", a.Handler).
				WithField("reason_id", "unknown_authentication_handler").
				Warn("Unknown authentication handler requested")
			return nil, err
		}
        //看一下这个认证器的配置是否符合要求
		if err := anh.Validate(a.Config); err != nil {
			d.r.Logger().WithError(err).
				WithFields(fields).
				WithField("granted", false).
				WithField("authentication_handler", a.Handler).
				WithField("reason_id", "invalid_authentication_handler").
				Warn("Unable to validate use of authentication handler")
			return nil, err
		}
      //执行认证过程,除非遇到ErrAuthenticatorNotResponsible错误,否则,都会返回该认证器的结果
		err = anh.Authenticate(r, session, a.Config, rl)
		if err != nil {
			switch errors.Cause(err).Error() {
			case authn.ErrAuthenticatorNotResponsible.Error():
				// 如果有该异常,则尝试下一个认证器
				break
			case helper.ErrUnauthorized.ErrorField:
				d.r.Logger().Info(err)
				return nil, err
			default:
				d.r.Logger().WithError(err).
					WithFields(fields).
					WithField("granted", false).
					WithField("authentication_handler", a.Handler).
					WithField("reason_id", "authentication_handler_error").
					Warn("The authentication handler encountered an error")
				return nil, err
			}
		} else {
			// The first authenticator that matches must return the session
			found = true
			fields["subject"] = session.Subject
			break
		}
	}
    /*
      没有找到可用的认证器时,返回错误
    */
	if !found {
		err := errors.WithStack(helper.ErrUnauthorized)
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("reason_id", "authentication_handler_no_match").
			Warn("No authentication handler was responsible for handling the authentication request")
		return nil, err
	}
	//找到该服务器是否支持该认证器
	azh, err := d.r.PipelineAuthorizer(rl.Authorizer.Handler)
	if err != nil {
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("authorization_handler", rl.Authorizer.Handler).
			WithField("reason_id", "unknown_authorization_handler").
			Warn("Unknown authentication handler requested")
		return nil, err
	}
    //查看配置是否符合该验证器的要求
	if err := azh.Validate(rl.Authorizer.Config); err != nil {
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("authorization_handler", rl.Authorizer.Handler).
			WithField("reason_id", "invalid_authorization_handler").
			Warn("Unable to validate use of authorization handler")
		return nil, err
	}
    //执行认证过程
	if err := azh.Authorize(r, session, rl.Authorizer.Config, rl); err != nil {
		d.r.Logger().
			WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("authorization_handler", rl.Authorizer.Handler).
			WithField("reason_id", "authorization_handler_error").
			Warn("The authorization handler encountered an error")
		return nil, err
	}

	if len(rl.Mutators) == 0 {
		err = errors.New("No mutation handler was set in the rule")
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			WithField("reason_id", "mutation_handler_missing").
			Warn("No mutation handler was set in the rule")
		return nil, err
	}

	//header变形器
	for _, m := range rl.Mutators {
		sh, err := d.r.PipelineMutator(m.Handler)
		if err != nil {
			d.r.Logger().WithError(err).
				WithFields(fields).
				WithField("granted", false).
				WithField("access_url", r.URL.String()).
				WithField("mutation_handler", m.Handler).
				WithField("reason_id", "unknown_mutation_handler").
				Warn("Unknown mutator requested")
			return nil, err
		}

		if err := sh.Validate(m.Config); err != nil {
			d.r.Logger().WithError(err).
				WithFields(fields).
				WithField("granted", false).
				WithField("mutation_handler", m.Handler).
				WithField("reason_id", "invalid_mutation_handler").
				Warn("Invalid mutator requested")
			return nil, err
		}

		if err := sh.Mutate(r, session, m.Config, rl); err != nil {
			d.r.Logger().WithError(err).
				WithFields(fields).
				WithField("granted", false).
				WithField("mutation_handler", m.Handler).
				WithField("reason_id", "mutation_handler_error").
				Warn("The mutation handler encountered an error")
			return nil, err
		}
	}

	return session, nil
}

2  将请求发到后端服务

    反向代理执行RoundTrip函数将请求发往后端,并得到服务端响应:

    

func (d *Proxy) RoundTrip(r *http.Request) (*http.Response, error) {
	rw := NewSimpleResponseWriter()
	fields := map[string]interface{}{
		"http_method":     r.Method,
		"http_url":        r.URL.String(),
		"http_host":       r.Host,
		"http_user_agent": r.UserAgent(),
	}

	if sess, ok := r.Context().Value(ContextKeySession).(*authn.AuthenticationSession); ok {
		fields["subject"] = sess.Subject
	}

	rl, _ := r.Context().Value(ContextKeyMatchedRule).(*rule.Rule)
    
	if err, ok := r.Context().Value(director).(error); ok && err != nil {
        //如果认证时存在错误,则将错误信息返回给客户端
		d.r.Logger().WithError(err).
			WithFields(fields).
			WithField("granted", false).
			Warn("Access request denied")

		d.r.ProxyRequestHandler().HandleError(rw, r, rl, err)

		return &http.Response{
			StatusCode: rw.code,
			Body:       ioutil.NopCloser(rw.buffer),
			Header:     rw.header,
		}, nil
	} else if err == nil {
        //认证成功,把请求发给后端
		res, err := http.DefaultTransport.RoundTrip(r)
		if err != nil {
			d.r.Logger().
				WithError(errors.WithStack(err)).
				WithField("granted", false).
				WithFields(fields).
				Warn("Access request denied because roundtrip failed")
			// don't need to return because covered in next line
		} else {
			d.r.Logger().
				WithField("granted", true).
				WithFields(fields).
				Warn("Access request granted")
		}

		return res, err
	}

	err := errors.New("Unable to type assert context")
	d.r.Logger().
		WithError(err).
		WithField("granted", false).
		WithFields(fields).
		Warn("Unable to type assert context")

	d.r.ProxyRequestHandler().HandleError(rw, r, rl, err)

	return &http.Response{
		StatusCode: rw.code,
		Body:       ioutil.NopCloser(rw.buffer),
		Header:     rw.header,
	}, nil
}

3  反思

     对于后续的开发过程中,对于Oathkeeper应该主要两个开发方向:

        (1) 当收到HTTP请求后,增加除了认证用户、授权用户的其他操作,比如:从数据库中读取设备信息、验证设备信息、收集设备信息等内容,对于这类需求,直接在proxy.Director增加相应步骤即可。

        (2) 增加认证、授权等其他组件,对于这类需求,可以按着如下步骤完成:

              step1:在driver\registry_memory.go文件中对对应组件进行注册;

              step2:完成相应认证、授权器,并加在authn,authz模块下

              step3:进行配置,使用相应组件

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值