예제 #1
0
// アクセストークンを使って、ID プロバイダからアカウント情報を取得する。
func (this *environment) getAccountInfo(req *callbackRequest, tok *token.Element, idp idpdb.Element) (attrs map[string]interface{}, err error) {
	acntReq, err := http.NewRequest("GET", idp.AccountUri(), nil)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	acntReq.Header.Set(tagAuthorization, tagBearer+" "+tok.Id())

	server.LogRequest(level.DEBUG, acntReq, this.debug, this.logPref)
	resp, err := http.DefaultClient.Do(acntReq)
	if err != nil {
		return nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	server.LogResponse(level.DEBUG, resp, this.debug, this.logPref)
	log.Info(this.logPref, "Got account info response from "+idp.Id())

	if err := json.NewDecoder(resp.Body).Decode(&attrs); err != nil {
		return nil, erro.Wrap(err)
	}
	log.Info(this.logPref, "Got account info")

	return attrs, nil
}
예제 #2
0
func (this *environment) serve(w http.ResponseWriter, r *http.Request) error {
	req, err := parseRequest(r)
	if err != nil {
		return erro.Wrap(idperr.New(idperr.Invalid_request, erro.Unwrap(err).Error(), http.StatusBadRequest, err))
	}

	var acntTag string
	tags := map[string]bool{}
	var refHash string
	type idpUnit struct {
		idp    idpdb.Element
		codTok *codeToken
	}
	units := []*idpUnit{}
	for _, rawCodTok := range req.codeTokens() {
		codTok, err := parseCodeToken(rawCodTok)
		if err != nil {
			return erro.Wrap(idperr.New(idperr.Invalid_request, erro.Unwrap(err).Error(), http.StatusBadRequest, err))
		} else if !codTok.audience()[this.selfId] {
			return erro.Wrap(idperr.New(idperr.Invalid_request, "invalid audience", http.StatusBadRequest, nil))
		} else if codTok.referralHash() == "" && len(req.codeTokens()) > 1 {
			return erro.Wrap(idperr.New(idperr.Invalid_request, "no referral hash", http.StatusBadRequest, nil))
		} else if codTok.accountTag() != "" {
			if acntTag != "" {
				return erro.Wrap(idperr.New(idperr.Invalid_request, "two main token", http.StatusBadRequest, nil))
			}
			acntTag = codTok.accountTag()
			log.Debug(this.logPref, "Main account tag is "+acntTag)
			if codTok.fromTa() == "" {
				return erro.Wrap(idperr.New(idperr.Invalid_request, "no from-TA in main token", http.StatusBadRequest, nil))
			}
			log.Debug(this.logPref, "From-TA is "+codTok.fromTa())
		} else if len(codTok.accountTags()) == 0 {
			return erro.Wrap(idperr.New(idperr.Invalid_request, "no account tags in sub token", http.StatusBadRequest, nil))
		}

		for tag := range codTok.accountTags() {
			if tags[tag] {
				return erro.Wrap(idperr.New(idperr.Invalid_request, "tag "+tag+" overlaps", http.StatusBadRequest, nil))
			}
			tags[tag] = true
			log.Debug(this.logPref, "Account tag is "+tag)
		}

		if codTok.referralHash() != "" {
			if refHash == "" {
				refHash = codTok.referralHash()
			} else if codTok.referralHash() != refHash {
				return erro.Wrap(idperr.New(idperr.Invalid_request, "invalid referral hash", http.StatusBadRequest, nil))
			}
		}

		var idp idpdb.Element
		if idp, err = this.idpDb.Get(codTok.idProvider()); err != nil {
			return erro.Wrap(err)
		} else if idp == nil {
			return erro.Wrap(idperr.New(idperr.Invalid_request, "ID provider "+codTok.idProvider()+" is not exist", http.StatusBadRequest, nil))
		}

		log.Debug(this.logPref, "ID provider "+idp.Id()+" is exist")

		if err := codTok.verify(idp.Keys()); err != nil {
			return erro.Wrap(idperr.New(idperr.Invalid_request, erro.Unwrap(err).Error(), http.StatusBadRequest, err))
		}

		log.Debug(this.logPref, "Verified cooperation code")

		units = append(units, &idpUnit{idp, codTok})
	}
	if acntTag == "" {
		return erro.Wrap(idperr.New(idperr.Invalid_request, "no main account tag", http.StatusBadRequest, nil))
	}

	log.Debug(this.logPref, "Cooperation codes are OK")

	var tok *token.Element
	var mainAttrs map[string]interface{}
	tagToAttrs := map[string]map[string]interface{}{}
	var frTa string
	for _, unit := range units {
		var tToA map[string]map[string]interface{}
		var fT string
		if unit.codTok.accountTag() != "" {
			fT, tok, tToA, err = this.getInfoFromMainIdProvider(unit.idp, unit.codTok)
			if err != nil {
				return erro.Wrap(err)
			}
			log.Debug(this.logPref, "Got account info from main ID provider "+unit.idp.Id())
		} else {
			fT, tToA, err = this.getInfoFromSubIdProvider(unit.idp, unit.codTok)
			if err != nil {
				return erro.Wrap(err)
			}
			log.Debug(this.logPref, "Got account info from sub ID provider "+unit.idp.Id())
		}
		for tag, attrs := range tToA {
			if tag == acntTag {
				attrs[tagIss] = unit.idp.Id()
				attrs[tagAt_tag] = tok.Tag()
				attrs[tagAt_exp] = tok.Expires().Unix()
				mainAttrs = attrs
			} else {
				attrs[tagIss] = unit.idp.Id()
				tagToAttrs[tag] = attrs
			}
		}
		if frTa == "" {
			frTa = fT
		} else if frTa != fT {
			return erro.Wrap(idperr.New(idperr.Invalid_request, "two from-TA ID", http.StatusBadRequest, nil))
		}
	}

	log.Debug(this.logPref, "Got all account info")

	jt := jwt.New()
	jt.SetHeader(tagAlg, tagNone)
	for k, v := range mainAttrs {
		jt.SetClaim(k, v)
	}
	mainInfo, err := jt.Encode()
	if err != nil {
		return erro.Wrap(err)
	}

	var relInfo []byte
	sessFlag := true
	if len(tagToAttrs) > 0 {
		jt = jwt.New()
		jt.SetHeader(tagAlg, tagNone)
		for acntTag, attrs := range tagToAttrs {
			jt.SetClaim(acntTag, attrs)
			if sessFlag {
				for k := range attrs {
					if !sessionEnable(k) {
						sessFlag = false
					}
				}
			}
		}
		relInfo, err = jt.Encode()
		if err != nil {
			return erro.Wrap(err)
		}
	}

	w.Header().Set(tagX_auth_user, string(mainInfo))
	w.Header().Set(tagX_auth_user_tag, acntTag)
	w.Header().Set(tagX_auth_from_id, frTa)
	if relInfo != nil {
		w.Header().Set(tagX_auth_users, string(relInfo))
	}
	if sessFlag {
		sessId := this.idGen.String(this.sessLen)
		http.SetCookie(w, this.handler.newCookie(sessId, tok.Expires()))
		log.Debug(this.logPref, "Report session "+logutil.Mosaic(sessId))
	}
	return nil
}