2018年10月25日木曜日

git credential で独自のヘルパを作ってみた

概要

前回 git-credential のビルトインの機能を使ってみました
そこでヘルパは任意のスクリプトで実装できることを知りました
今回は独自のヘルパを Ruby + Redis で作ってみました
Redis に認証情報を格納してそれを取り出し Github などの認証ができるようになります

バージョン

  • Ubuntu 18.01
  • Ruby 2.5.1p57
  • Redis 4.0.9

事前準備

  • apt -y install redis-server

ライブラリインストール

  • gem install redis

スクリプトを PATH 上に配置する関係でグローバルインストールします

ヘルパスクリプト

  • vim /usr/local/bin/git-credential-redis-helper
#!/usr/bin/env ruby

require 'redis'
require 'json'
require 'erb'
require 'securerandom'

class RedisHelper
  def initialize
    @redis = Redis.new
  end

  def list
    @redis.keys.map { |key|
      {key => @redis.get(key)}
    }
  end

  def get
    known = {}
    while line = STDIN.gets
      break if line.strip == ''
      k,v = line.strip.split '=', 2
      known[k] = v
    end
    @auth = {}
    list.each { |auths|
      auths.each { |k,v|
        auth = JSON.parse(v)
        if auth["protocol"] == known["protocol"] and auth["host"] == known["host"]
          @auth = auth
          break
        end
      }
    }
    erb = ERB.new(File.read("/usr/local/bin/auth.erb"))
    erb.result(binding)
  end

  def store
  end  

  def qstore(key, value)
    @redis.set(key, value)
  end

  def erase(key)
    @redis.del(key)
  end
end

def main
  rh = RedisHelper.new
  command = ARGV[0]
  case command
  when 'list' then
    puts rh.list
  when 'get' then
    puts rh.get
  when 'store' then
    rh.store
  when 'qstore' then
    rh.qstore(ARGV[1], ARGV[2])
  when 'erase' then
    rh.erase(ARGV[1])
  else
  end
end
  • chmod 755 /usr/local/bin/git-credential-redis-helper

拡張子なしで作成するためシェバングを付与しています
git からコールされるため実行権限を付与します

説明

main 関数を用意したのでそこから見ると良いと思います
引数のコマンドに応じて redis に対する処理が変わってきます

get

必ず実装しなければいけないのが get です

get は標準入力を受け取って、その入力条件に当てはまる認証情報を redis から取得します
そして決められたフォーマットで認証情報を標準出力します
今回の redis のフォーマットは SET を使って key + hash として認証情報を登録することを想定しています
hash 側に認証情報があるのでそこと比較して当てはまるものがあれば erb でフォーマットして出力している感じです

redis に登録する際のフォーマットは改良の余地ありかなと思います
また、erb も必須ではありません
改行などもあるので、今回は使いましたが直接 puts しても問題ないです

qstore

引数に key + hash を取りそれをそのまま redis に格納します
store とコマンド名がかぶらないように q を付与しています

list

list は確認用の便利コマンドとして用意しました
redis 内にあるすべての key 情報に対してデータを取得して表示してくれます

erase

指定の key を redis から削除してくれます

store

不明
後で実行方法を紹介しますが、おそらくこれがちゃんと実装されていれば一度目の認証情報をちゃんと redis に格納できるようになるんだと思います

テンプレートファイルの配置

  • vim /usr/local/bin/auth.erb
protocol=<%= @auth["protocol"] %>
host=<%= @auth["host"] %>
username=<%= @auth["username"] %>
password=<%= @auth["password"] %>

これは正直なくてもいいかもしれません
直接スクリプト内で puts しても OK です

動作確認 (使い方)

redis-server は起動しておきましょう
また現状は localhost:6379 でのみ動作していることを想定しています

まず認証情報を登録します

git credential-redis-helper qstore 'github' '{"protocol":"https","host":"github.com","username":"hawksnowlog","password":"xxxxxxxx"}'

こんな感じです
別に Github の情報でなくても OK です
登録した認証情報は list コマンドで確認できます

  • git credential-redis-helper list

また git credential-redis-helper get はインタラクティブに認証情報を検索することができます
これは store や cache ヘルパと同じ仕様になります

登録したら認証が聞かれるか確認してみましょう
Github の場合であれば push 時に認証が聞かれなければ OK です

登録した認証情報を削除したい場合は

  • git credential-redis-helper erase github

で可能です
もちろん redis-cli でログインして DEL しても OK です

最後に

git credential で独自のヘルパスクリプトを実装してみました
今回は Ruby + Redis で開発しましたが、同じように別の言語や RDB でも実装可能です
store の挙動がよくわからなかったので今回の仕様では事前に redis に認証情報を登録する必要が出てしましました
本来は一度目の認証を redis に登録してそれ以降は redis にある認証情報を使いたかったのです

その辺りの問題を解決して、もう少しリファクタリングすれば公開できるかなと思います (ホスト名の指定やパスワード情報の暗号化なども実装したほうが良いかなと思います)
redis をインストールする必要もあるので需要があるか不明ですが

0 件のコメント:

コメントを投稿