func rotateFile(path string, num int) error { var n int for n = 1; n < num; n++ { _, err := os.Stat(path + "." + strconv.Itoa(n)) if err == nil { continue } else if os.IsNotExist(err) { break } else { return erro.Wrap(err) } } n-- // .{n} が残す中で一番最後。 // .{i} を .{i+1} に。 for ; n > 0; n-- { from := path + "." + strconv.Itoa(n) to := path + "." + strconv.Itoa(n+1) if err := os.Rename(from, to); err != nil { return erro.Wrap(err) } } // 最新版 を .1 に。 if err := os.Rename(path, path+".1"); err != nil { return erro.Wrap(err) } return nil }
func (core *fluentdCoreHandler) flushCore(writeSize int) { for retry := false; ; retry = true { if core.conn == nil { var err error core.conn, err = net.Dial("tcp", core.addr) if err != nil { // 接続出来なければ諦める。 fmt.Fprintln(os.Stderr, erro.Wrap(err)) return } core.buff.setSink(core.conn) } // 接続はある。 err := core.buff.flushIfNeeded(writeSize) if err == nil { // 書き込み成功。 return } // 書き込み失敗。 // 接続が古くてサーバー側に切断されていたとか。 fmt.Fprintln(os.Stderr, erro.Wrap(err)) core.conn.Close() core.conn = nil if retry { // 接続しなおしても書き込めないなら諦める。 return } } }
func parseCodeToken(raw []byte) (*codeToken, error) { base, err := jwt.Parse(raw) if err != nil { return nil, erro.Wrap(err) } var buff struct { Idp string `json:"iss"` Cod string `json:"sub"` Aud audience.Audience `json:"aud"` FrTa string `json:"from_client"` AcntTag string `json:"user_tag"` AcntTags strset.Set `json:"user_tags"` RefHash string `json:"ref_hash"` } if err := json.Unmarshal(base.RawBody(), &buff); err != nil { return nil, erro.Wrap(err) } else if buff.Idp == "" { return nil, erro.New("no ID provider ID") } else if buff.Cod == "" { return nil, erro.New("no code") } else if len(buff.Aud) == 0 { return nil, erro.New("no audience") } return &codeToken{ base: base, idp: buff.Idp, cod: buff.Cod, aud: buff.Aud, frTa: buff.FrTa, acntTag: buff.AcntTag, acntTags: buff.AcntTags, refHash: buff.RefHash, }, nil }
func newTestSingleRequestWithParams(hndl *handler, idp idpdb.Element, params map[string]interface{}) (*http.Request, error) { r, err := http.NewRequest("GET", "http://localhost/coop", nil) if err != nil { return nil, erro.Wrap(err) } codTok := jwt.New() codTok.SetHeader("alg", test_idpSigAlg) codTok.SetClaim("iss", idp.Id()) codTok.SetClaim("sub", test_cod) codTok.SetClaim("aud", audience.New(hndl.selfId)) codTok.SetClaim("from_client", test_frTa.Id()) codTok.SetClaim("user_tag", test_acntTag) codTok.SetClaim("user_tags", []string{test_subAcnt1Tag}) for k, v := range params { codTok.SetClaim(k, v) } if err := codTok.Sign(idp.Keys()); err != nil { return nil, erro.Wrap(err) } data, err := codTok.Encode() if err != nil { return nil, erro.Wrap(err) } r.Header.Set("X-Edo-Code-Tokens", string(data)) return r, nil }
func setupKeyDb(path string, keys []jwk.Key) (dir string, err error) { dir, err = ioutil.TempDir(filepath.Dir(path), filepath.Base(path)) for i, key := range keys { if data, err := json.Marshal(key.ToMap()); err != nil { return "", erro.Wrap(err) } else if ioutil.WriteFile(filepath.Join(dir, strconv.Itoa(i)+".json"), data, 0644); err != nil { return "", erro.Wrap(err) } } return dir, nil }
func NewFileHandlerUsing(path string, fmter Formatter) (Handler, error) { if err := os.MkdirAll(filepath.Dir(path), dirPerm); err != nil { return nil, erro.Wrap(err) } // file の Close はプログラムの終処理任せ。 sink, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, filePerm) if err != nil { return nil, erro.Wrap(err) } return NewCloseHandlerUsing(sink, fmter), nil }
// 解放する。 func (lock *Locker) Unlock() error { file := (*os.File)(lock) if err := syscall.Flock(int(file.Fd()), syscall.LOCK_UN); err != nil { return erro.Wrap(err) } if err := file.Close(); err != nil { return erro.Wrap(err) } return nil }
func newTestMainIdpResponseWithParams(hndl *handler, idp idpdb.Element, params, idsTokParams map[string]interface{}) (status int, header http.Header, body []byte, err error) { now := time.Now() idsTok := jwt.New() idsTok.SetHeader("alg", test_idpSigAlg) idsTok.SetClaim("iss", idp.Id()) idsTok.SetClaim("sub", test_frTa.Id()) idsTok.SetClaim("aud", audience.New(hndl.selfId)) idsTok.SetClaim("exp", now.Add(time.Minute).Unix()) idsTok.SetClaim("iat", now.Unix()) idsTok.SetClaim("ids", map[string]map[string]interface{}{ test_acntTag: { "sub": test_acntId, "email": test_acntEmail, }, test_subAcnt1Tag: { "sub": test_subAcnt1Id, "email": test_subAcnt1Email, }, }) for k, v := range idsTokParams { idsTok.SetClaim(k, v) } if err := idsTok.Sign(idp.Keys()); err != nil { return 0, nil, nil, erro.Wrap(err) } data, err := idsTok.Encode() if err != nil { return 0, nil, nil, erro.Wrap(err) } m := map[string]interface{}{ "access_token": test_tok, "token_type": "Bearer", "expires_in": 1234, "scope": "openid email", "ids_token": string(data), } for k, v := range params { if v == nil { delete(m, k) } else { m[k] = v } } body, err = json.Marshal(m) if err != nil { return 0, nil, nil, erro.Wrap(err) } return http.StatusOK, http.Header{"Content-Type": {"application/json"}}, body, nil }
func testFilePath() (path string, err error) { file, err := ioutil.TempFile("", "test_") if err != nil { return "", erro.Wrap(err) } if err := file.Close(); err != nil { return "", erro.Wrap(err) } if err := os.Remove(file.Name()); err != nil { return "", erro.Wrap(err) } return file.Name(), nil }
func (core *syslogCoreHandler) output(rec Record) { // {レベル} {ファイル名}:{行番号} {メッセージ} // 日時は syslog が付ける。 msg := fmt.Sprintf("%."+strconv.Itoa(lvWidth)+"v %s:%d %s\n", rec.Level(), rec.File(), rec.Line(), rec.Message()) for retry := false; ; retry = true { if core.base == nil { var err error core.base, err = syslog.Dial("", core.addr, syslog.LOG_INFO, core.tag) if err != nil { // 初期化出来なければ諦める。 fmt.Fprintln(os.Stderr, erro.Wrap(err)) fmt.Fprintln(os.Stderr, "Drop log: "+string(SimpleFormatter.Format(rec))) return } } // 初期化してある。 var err error switch rec.Level() { case level.ERR: err = core.base.Err(msg) case level.WARN: err = core.base.Warning(msg) case level.INFO: err = core.base.Info(msg) case level.DEBUG: err = core.base.Debug(msg) } if err == nil { // 書き込み成功。 return } // 書き込み失敗。 // 初期化が古くてサーバー側で何か変わったとか。 fmt.Fprintln(os.Stderr, erro.Wrap(err)) core.base.Close() core.base = nil if retry { // 初期化しなおしても書き込めないなら諦める。 fmt.Fprintln(os.Stderr, "Drop log: "+string(SimpleFormatter.Format(rec))) return } } }
func (core *rotateCoreHandler) flushCore(writeSize int) { // ロックファイルをつくったほうが良いが、OS 依存なので止めとく。 for { if core.file == nil { // ファイルを開く。 if err := os.MkdirAll(filepath.Dir(core.path), dirPerm); err != nil { fmt.Fprintln(os.Stderr, erro.Wrap(err)) return } var err error core.file, err = os.OpenFile(core.path, os.O_RDWR|os.O_APPEND|os.O_CREATE, filePerm) if err != nil { fmt.Fprintln(os.Stderr, erro.Wrap(err)) return } if err := core.buff.setSink(core.file); err != nil { fmt.Fprintln(os.Stderr, erro.Wrap(err)) return } } // ファイルを開いている。 err := core.buff.flushIfNeeded(writeSize) switch err { case nil: // 書き込み成功。 return case fileIsFull: // ローテートする。 core.file.Close() core.file = nil if err := rotateFile(core.path, core.num); err != nil { fmt.Fprintln(os.Stderr, erro.Wrap(err)) return } continue default: fmt.Fprintln(os.Stderr, erro.Wrap(err)) core.file.Close() core.file = nil return } } }
// 保存。 func (this *redisDb) Save(elem *Element, exp time.Time) error { conn := this.pool.Get() defer conn.Close() data, err := json.Marshal(elem) if err != nil { return erro.Wrap(err) } expIn := int64(exp.Sub(time.Now()) / time.Millisecond) if _, err := conn.Do("SET", this.tag+elem.Tag(), data, "PX", expIn); err != nil { return erro.Wrap(err) } return nil }
func parseCoopResponse(resp *http.Response) (*coopResponse, error) { if resp.StatusCode != http.StatusOK { return nil, erro.New("invalid state ", resp.StatusCode) } else if contType := resp.Header.Get(tagContent_type); contType != contTypeJson { return nil, erro.New("invalid content type " + contType) } var buff struct { Tok string `json:"access_token"` TokType string `json:"token_type"` ExpIn int `json:"expires_in"` Scop string `json:"scope"` IdsTok string `json:"ids_token"` } if err := json.NewDecoder(resp.Body).Decode(&buff); err != nil { return nil, erro.Wrap(err) } else if buff.IdsTok == "" { return nil, erro.New("cannot get IDs token") } return &coopResponse{ tok: buff.Tok, tokType: buff.TokType, expIn: time.Duration(buff.ExpIn) * time.Second, scop: requtil.FormValueSet(buff.Scop), idsTok: []byte(buff.IdsTok), }, nil }
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 } }
func setupIdpDb(db, coll string, idps []idpdb.Element) error { conn := monPool.New() defer conn.Close() for _, idp := range idps { keys := []map[string]interface{}{} for _, key := range idp.Keys() { keys = append(keys, key.ToMap()) } m := bson.M{ "issuer": idp.Id(), "authorization_endpoint": idp.AuthUri(), "token_endpoint": idp.TokenUri(), "userinfo_endpoint": idp.AccountUri(), "cooperation_from_endpoint": idp.CoopFromUri(), "cooperation_to_endpoint": idp.CoopToUri(), "jwks": keys, } for k, v := range idp.Names() { if k == "" { m["issuer_name"] = v } else { m["issuer_name#"+k] = v } } if err := conn.DB(db).C(coll).Insert(m); err != nil { return erro.Wrap(err) } } return nil }
func (buff *fileLogBuffer) flush() error { n := 0 writeBuff := []byte{} for elem := buff.unwritten.Front(); elem != nil; elem = elem.Next() { log := elem.Value.([]byte) if curSize := buff.sinkSize + len(writeBuff); curSize > 0 && // サイズオーバーしても 1 個は必ず書く。 curSize+len(log) > buff.limit { break } writeBuff = append(writeBuff, log...) n++ } if _, err := buff.sink.Write(writeBuff); err != nil { return erro.Wrap(err) } buff.sinkSize += len(writeBuff) if n == buff.unwritten.Len() { // 全部書き出した。 buff.unwritten.Init() buff.unwrittenSize = 0 return nil } // n 個だけ書き出した。 for i := 0; i < n; i++ { buff.unwritten.Remove(buff.unwritten.Front()) } buff.unwrittenSize -= len(writeBuff) return fileIsFull }
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 }
func newTestIdProvider(keys []jwk.Key) (*testIdProvider, error) { base, err := test.NewHttpServer(time.Minute) if err != nil { return nil, erro.Wrap(err) } return &testIdProvider{base, keys}, nil }
// ユーザー認証開始。 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 }
func (this *Element) UnmarshalJSON(data []byte) error { var buff struct { Id string `json:"id"` Inv bool `json:"invalid"` Exp time.Time `json:"expires"` Path string `json:"path"` Idp string `json:"id_provider"` Ta string `json:"client_id"` RediUri string `json:"redirect_uri"` Stat string `json:"state"` Nonc string `json:"nonce"` Date time.Time `json:"date"` } if err := json.Unmarshal(data, &buff); err != nil { return erro.Wrap(err) } this.id = buff.Id this.inv = buff.Inv this.exp = buff.Exp this.path = buff.Path this.idp = buff.Idp this.ta = buff.Ta this.rediUri = buff.RediUri this.stat = buff.Stat this.nonc = buff.Nonc this.date = buff.Date return nil }
func parseTokenResponse(resp *http.Response) (*tokenResponse, error) { var buff struct { Access_token string Expires_in int Scope string Id_token string } if err := json.NewDecoder(resp.Body).Decode(&buff); err != nil { return nil, erro.Wrap(err) } else if buff.Access_token == "" { return nil, erro.New("no access token") } var exp time.Time if buff.Expires_in != 0 { exp = time.Now().Add(time.Duration(buff.Expires_in) * time.Second) } var scop map[string]bool if buff.Scope != "" { scop = request.FormValueSet(buff.Scope) } var idTok []byte if buff.Id_token != "" { idTok = []byte(buff.Id_token) } return &tokenResponse{ tok: buff.Access_token, exp: exp, scop: scop, idTok: idTok, }, nil }
func (core *syslogCoreHandler) close() { core.flush() if err := core.base.Close(); err != nil { err = erro.Wrap(err) fmt.Fprintln(os.Stderr, err) } }
func newAuthRequest() (*http.Request, error) { r, err := http.NewRequest("GET", "http://localhost/", nil) if err != nil { return nil, erro.Wrap(err) } r.Header.Set("X-Auth-Uri", test_idp.AuthUri()) return r, nil }
func (v levelVar) Set(s string) error { var err error *v.Level, err = ValueOf(s) if err != nil { return erro.Wrap(err) } return nil }
func parseIdToken(raw []byte) (*idToken, error) { base, err := jwt.Parse(raw) if err != nil { return nil, erro.Wrap(err) } alg, _ := base.Header(tagAlg).(string) if alg == "" { return nil, erro.New("no alg") } var buff struct { Idp string `json:"iss"` Nonc string `json:"nonce"` CHash string `json:"c_hash"` AtHash string `json:"at_hash"` } if err := json.Unmarshal(base.RawBody(), &buff); err != nil { return nil, erro.Wrap(err) } else if buff.Idp == "" { return nil, erro.New("no ID provider ID") } else if buff.Nonc == "" { return nil, erro.New("no nonce") } var cHash, atHash []byte if buff.CHash != "" { cHash, err = base64.RawURLEncoding.DecodeString(buff.CHash) if err != nil { return nil, erro.Wrap(err) } } if buff.AtHash != "" { atHash, err = base64.RawURLEncoding.DecodeString(buff.AtHash) if err != nil { return nil, erro.Wrap(err) } } return &idToken{ base: base, alg: alg, idp: buff.Idp, nonc: buff.Nonc, cHash: cHash, atHash: atHash, }, nil }
func newAuthRequest(uri, idpUri string) (*http.Request, error) { r, err := http.NewRequest("GET", uri, nil) if err != nil { return nil, erro.Wrap(err) } r.Header.Set("X-Auth-Uri", idpUri) r.Header.Set("Connection", "close") return r, nil }
func (hndl *flushHandler) Flush() { hndl.lock.Lock() defer hndl.lock.Unlock() if err := hndl.flusher.Flush(); err != nil { err = erro.Wrap(err) fmt.Fprintln(os.Stderr, err) } }
func (buff *fileLogBuffer) setSink(sink *os.File) error { stat, err := sink.Stat() if err != nil { return erro.Wrap(err) } buff.sink = sink buff.sinkSize = int(stat.Size()) return nil }
func lock(path string, flag int) (*Locker, error) { file, err := os.Create(path) if err != nil { return nil, erro.Wrap(err) } if err := syscall.Flock(int(file.Fd()), syscall.LOCK_EX|flag); err != nil { file.Close() if err == syscall.EWOULDBLOCK { // ロックできなかった。 return nil, nil } return nil, erro.Wrap(err) } return (*Locker)(file), nil }
func (this *redisDb) Save(elem *Element, exp time.Time) error { conn := this.pool.Get() defer conn.Close() data, err := json.Marshal(elem) if err != nil { return erro.Wrap(err) } expIn := int64(exp.Sub(time.Now()) / time.Millisecond) conn.Send("MULTI") conn.Send("SET", this.tag+elem.Id(), data, "PX", expIn) conn.Send("SET", this.tag+tagDate+elem.Id(), elem.Date().UnixNano(), "PX", expIn) if _, err := conn.Do("EXEC"); err != nil { return erro.Wrap(err) } return nil }