// アクセストークンを使って、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 }
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 }