// 認可コードを使って、ID プロバイダからアクセストークンを取得する。 func (this *environment) getAccessToken(req *callbackRequest, idp idpdb.Element) (*token.Element, *idToken, error) { keys, err := this.keyDb.Get() if err != nil { return nil, nil, erro.Wrap(err) } queries := url.Values{} // grant_type queries.Set(tagGrant_type, tagAuthorization_code) // code queries.Set(tagCode, req.code()) // redirect_uri queries.Set(tagRedirect_uri, this.sess.RedirectUri()) // client_id queries.Set(tagClient_id, this.sess.Ta()) // client_assertion_type queries.Set(tagClient_assertion_type, cliAssTypeJwt_bearer) // client_assertion ass := jwt.New() now := time.Now() ass.SetHeader(tagAlg, this.sigAlg) ass.SetClaim(tagIss, this.sess.Ta()) ass.SetClaim(tagSub, this.sess.Ta()) ass.SetClaim(tagAud, idp.TokenUri()) ass.SetClaim(tagJti, this.idGen.String(this.jtiLen)) ass.SetClaim(tagExp, now.Add(this.jtiExpIn).Unix()) ass.SetClaim(tagIat, now.Unix()) if err := ass.Sign(keys); err != nil { return nil, nil, erro.Wrap(err) } buff, err := ass.Encode() if err != nil { return nil, nil, erro.Wrap(err) } queries.Set(tagClient_assertion, string(buff)) tokReq, err := http.NewRequest("POST", idp.TokenUri(), strings.NewReader(queries.Encode())) if err != nil { return nil, nil, erro.Wrap(err) } tokReq.Header.Set(tagContent_type, contTypeForm) server.LogRequest(level.DEBUG, tokReq, this.debug, this.logPref) resp, err := http.DefaultClient.Do(tokReq) if err != nil { return nil, nil, erro.Wrap(err) } defer resp.Body.Close() server.LogResponse(level.DEBUG, resp, this.debug, this.logPref) log.Info(this.logPref, "Got token response from "+idp.Id()) tokResp, err := parseTokenResponse(resp) if err != nil { return nil, nil, erro.Wrap(server.NewError(http.StatusForbidden, "cannot get access token", nil)) } tok := token.New(tokResp.token(), this.idGen.String(this.tokTagLen), tokResp.expires(), idp.Id(), tokResp.scope()) log.Info(this.logPref, "Got access token "+logutil.Mosaic(tok.Id())) if err := this.tokDb.Save(tok, time.Now().Add(this.tokDbExpIn)); err != nil { return nil, nil, erro.Wrap(err) } log.Info(this.logPref, "Saved access token "+logutil.Mosaic(tok.Id())) idTok, err := parseIdToken(tokResp.idToken()) if err != nil { return nil, nil, erro.Wrap(server.NewError(http.StatusForbidden, erro.Unwrap(err).Error(), err)) } else if idTok.nonce() != this.sess.Nonce() { return nil, nil, erro.Wrap(server.NewError(http.StatusForbidden, "invalid nonce", nil)) } else if err := idTok.verify(idp.Keys()); err != nil { return nil, nil, erro.Wrap(server.NewError(http.StatusForbidden, erro.Unwrap(err).Error(), err)) } else if idTok.tokenHash() != nil { if err := idTok.verifyTokenHash(tok.Id()); err != nil { return nil, nil, erro.Wrap(server.NewError(http.StatusForbidden, erro.Unwrap(err).Error(), err)) } } log.Info(this.logPref, "ID token is OK") return tok, idTok, nil }