func (this *Page) HandleCallback(w http.ResponseWriter, r *http.Request) {
	var logPref string

	// panic 対策。
	defer func() {
		if rcv := recover(); rcv != nil {
			server.RespondErrorHtml(w, r, erro.New(rcv), this.errTmpl, logPref)
			return
		}
	}()

	if this.stopper != nil {
		this.stopper.Stop()
		defer this.stopper.Unstop()
	}

	sender := request.Parse(r, this.sessLabel)
	logPref = sender.String() + ": "

	server.LogRequest(level.DEBUG, r, this.debug, logPref)

	log.Info(logPref, "Received callback request")
	defer log.Info(logPref, "Handled callback request")

	if err := (&environment{this, logPref, sender.Session(), nil}).callbackServe(w, r); err != nil {
		server.RespondErrorHtml(w, r, erro.Wrap(err), this.errTmpl, logPref)
		return
	}
	return
}
Beispiel #2
0
func (this *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var logPref string

	// panic 対策。
	defer func() {
		if rcv := recover(); rcv != nil {
			w.Header().Set(tagX_edo_cooperation_error, fmt.Sprint(rcv))
			idperr.RespondJson(w, r, erro.New(rcv), logPref)
			return
		}
	}()

	if this.stopper != nil {
		this.stopper.Stop()
		defer this.stopper.Unstop()
	}

	logPref = server.ParseSender(r) + ": "

	server.LogRequest(level.DEBUG, r, this.debug, logPref)

	log.Info(logPref, "Received cooperation request")
	defer log.Info(logPref, "Handled cooperation request")

	if err := (&environment{this, logPref}).serve(w, r); err != nil {
		w.Header().Set(tagX_edo_cooperation_error, idperr.From(err).ErrorDescription())
		idperr.RespondJson(w, r, erro.Wrap(err), logPref)
		return
	}
}
Beispiel #3
0
// ユーザー認証開始。
func (this *Page) HandleAuth(w http.ResponseWriter, r *http.Request) {
	var logPref string

	// panic 対策。
	defer func() {
		if rcv := recover(); rcv != nil {
			server.RespondErrorHtml(w, r, erro.New(rcv), this.errTmpl, logPref)
			return
		}
	}()

	if this.stopper != nil {
		this.stopper.Stop()
		defer this.stopper.Unstop()
	}

	logPref = server.ParseSender(r) + ": "

	server.LogRequest(level.DEBUG, r, this.debug, logPref)

	log.Info(logPref, "Received authentication request")
	defer log.Info(logPref, "Handled authentication request")

	if err := (&environment{this, logPref, "", nil}).authServe(w, r); err != nil {
		server.RespondErrorHtml(w, r, erro.Wrap(err), this.errTmpl, logPref)
		return
	}
	return
}
Beispiel #4
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
}
Beispiel #5
0
// 認可コードを使って、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
}
Beispiel #6
0
func (this *environment) getInfo(isMain bool, idp idpdb.Element, codTok *codeToken) (frTa string, tok *token.Element, tagToAttrs map[string]map[string]interface{}, err error) {
	params := map[string]interface{}{}

	// grant_type
	params[tagGrant_type] = tagCooperation_code

	// code
	params[tagCode] = codTok.code()

	// claims
	if isMain {
		// TODO 受け取り方を考えないと。
	}

	// user_claims
	// TODO 受け取り方を考えないと。

	// client_assertion_type
	params[tagClient_assertion_type] = cliAssTypeJwt_bearer

	// client_assertion
	keys, err := this.keyDb.Get()
	if err != nil {
		return "", nil, nil, erro.Wrap(err)
	}
	ass, err := makeAssertion(this.handler, keys, idp.CoopToUri())
	if err != nil {
		return "", nil, nil, erro.Wrap(err)
	}
	params[tagClient_assertion] = string(ass)

	data, err := json.Marshal(params)
	if err != nil {
		return "", nil, nil, erro.Wrap(err)
	}

	r, err := http.NewRequest("POST", idp.CoopToUri(), bytes.NewReader(data))
	r.Header.Set(tagContent_type, contTypeJson)
	log.Debug(this.logPref, "Made main cooperation-to request")

	server.LogRequest(level.DEBUG, r, this.debug, this.logPref)
	resp, err := this.conn.Do(r)
	if err != nil {
		return "", nil, nil, erro.Wrap(err)
	}
	defer resp.Body.Close()
	server.LogResponse(level.DEBUG, resp, this.debug, this.logPref)

	if resp.StatusCode != http.StatusOK {
		var buff struct {
			Error             string
			Error_description string
		}
		if err := json.NewDecoder(resp.Body).Decode(&buff); err != nil {
			return "", nil, nil, erro.Wrap(err)
		}
		return "", nil, nil, erro.Wrap(idperr.New(buff.Error, buff.Error_description, resp.StatusCode, nil))
	}
	coopResp, err := parseCoopResponse(resp)
	if err != nil {
		return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, erro.Unwrap(err).Error(), http.StatusForbidden, err))
	}

	idsTok, err := parseIdsToken(coopResp.idsToken())
	if err != nil {
		return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, erro.Unwrap(err).Error(), http.StatusForbidden, err))
	} else if err := idsTok.verify(idp.Keys()); err != nil {
		return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, erro.Unwrap(err).Error(), http.StatusForbidden, err))
	}

	tagToAttrs = map[string]map[string]interface{}{}
	for acntTag := range codTok.accountTags() {
		attrs := idsTok.attributes()[acntTag]
		if attrs == nil {
			return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, "cannot get sub account tagged by "+acntTag, http.StatusForbidden, nil))
		}
		tagToAttrs[acntTag] = attrs
	}

	if isMain {
		attrs := idsTok.attributes()[codTok.accountTag()]
		if attrs == nil {
			return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, "cannot get main account tagged by "+codTok.accountTag(), http.StatusForbidden, nil))
		}
		tagToAttrs[codTok.accountTag()] = attrs

		if coopResp.token() == "" {
			return "", nil, nil, erro.Wrap(idperr.New(idperr.Access_denied, "cannot get token", http.StatusForbidden, nil))
		}
		now := time.Now()
		tok = token.New(coopResp.token(), this.idGen.String(this.tokTagLen), now.Add(coopResp.expiresIn()), idsTok.idProvider(), coopResp.scope())
		log.Info(this.logPref, "Got access token "+logutil.Mosaic(tok.Id()))

		if err := this.tokDb.Save(tok, now.Add(this.tokDbExpIn)); err != nil {
			return "", nil, nil, erro.Wrap(err)
		}
		log.Info(this.logPref, "Saved access token "+logutil.Mosaic(tok.Id()))
	}

	return idsTok.fromTa(), tok, tagToAttrs, nil
}