pac4jでGitHubのOAuth認証を使ってみる

GitHubアカウントでログインできるWebアプリケーションを作りたいなーと思っていたのですが、Javaだとpac4jというライブラリを使うとGitHubを始め、TwitterFacebookなど様々なサービスのOAuth認証を扱うことができるようです。

github.com

SpringMVCやJAX-RSなどのフレームワークとの連携機能も提供されているようですが、今回は基本的な使い方を把握するためにpac4j-oauthというモジュールを使ってサーブレットベースで試してみました。

まずはGitHub上でアプリケーションの登録を行う必要があります。

f:id:takezoe:20170128020846p:plain

続いてプログラムの実装に移ります。pom.xmlに以下の依存関係を追加します。

<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-oauth</artifactId>
    <version>1.9.5</version>
</dependency>

プログラムでは以下のようにしてGitHubClientを生成します。シングルトンなインスタンスとして生成しておくとよいと思います。コンストラクタの引数にはGitHubへのアプリケーション登録時に発行されたクライアントIDとクライアントシークレットを指定します。

GitHubClient client = new GitHubClient(clientId, secret);
client.setCallbackUrl("http://localhost:8080/callback");
client.setScope("repo, user");

コールバックURLは認証後にリダイレクトされるURL、スコープはアプリケーションが必要とする権限を指定します。GitHubで指定可能なスコープについてはこちらを参照してください(デフォルトはuserです)。

認証を要求するには以下のようにします。redirect()メソッドでGitHubの認証ページにリダイレクトされます。J2EContextというのはJavaEEサーブレット)用のアダプタみたいなものです。このクラスを差し替えることで別のフレームワークにも対応できる作りになっています。

J2EContext context = new J2EContext(request, response);
client.redirect(context);

f:id:takezoe:20170128021422p:plain

ユーザがこの画面でアプリケーションの認証要求を許可すると指定したコールバックURLにリダイレクトされるので、該当のURLを処理するサーブレットで以下のようなコードで認証情報を取得します。

J2EContext context = new J2EContext(request, response);
OAuthCredentials credentials = client.getCredentials(context);
GitHubProfile profile = client.getUserProfile(credentials, context);

profileからユーザ情報やAPI呼び出し用のアクセストークンなどを取得することができます。

String userName = profile.getUsername();
String email = profile.getEmail();
String accessToken = profile.getAccessToken();

こんな感じでpac4jを使うと簡単にGitHubOAuth認証を利用することができます。他のサービスの場合もGitHubClientの代わりにTwitterClientFacebookClientなどのクラスを使用するだけで同じような感じで実装することができます。また、OAuth以外にも様々な認証方式に対応したモジュールが提供されています。

特定のフレームワーク用のアドオンとしてだけではなく単独のライブラリとしても使えるようになっているのでJavaで外部サービスのアカウントを使用した認証機能が必要な場合は覚えておくといいんじゃないかと思います。

Apache DrillでExcelを検索するプラグインを作った

ExcelをDBに入っているデータとジョインできたら便利なのでは?ということで作ってみました。

github.com

GitHubリリースページからダウンロードしたjarファイルをDRILL_HOME/jars/3rdpartyにコピーし、ストレージ設定でdfsに以下のフォーマットの設定を追加します。

  "formats": {
    "excel": {
      "type": "excel",
      "extensions": [
        "xlsx"
      ]
    },
    ...
  }

するとDrillで*.xlsxファイルをSQLで検索できる様になります。もちろんDrillでアクセス可能な他のデータソース上のテーブルとジョインすることもできます。

0: jdbc:drill:zk=local> SELECT id, name FROM dfs.`/tmp/emp.xlsx` where age > 35.0;
+----------+----------------+
|    id    |      name      |
+----------+----------------+
| takezoe  | Naoki Takezoe  |
+----------+----------------+
1 row selected (3.118 seconds)

本当はシートをテーブルとして扱うようにしたかったのですが、Drillのdfsは1ファイルを1テーブルとして扱うためこのプラグインでは1シート目のデータしか使うことができません。また、カラム名として使用するためヘッダ行を入れておく必要があるという制約があります。まあネタで作ったようなものなのでこれらの点については目を瞑っていただけると幸いですw

以前LTSV用のプラグインも作ったのですが、Drillはこの手のプラグインは本当に簡単に実装することができますね。

takezoe.hatenablog.com

スターティングGo言語

先日紹介したみんなのGo言語電子書籍で購入したのですが、こちらはリファレンス用にペーパー版を購入しました。

スターティングGo言語

スターティングGo言語

言語仕様はきっちり押さえられていますし、言語機能を実際にどのような用途に使うべきかという説明や、落とし穴などについても触れられています。ツールや標準ライブラリの紹介もあるのでGo初心者は一度目を通しておくとよさそうです。

一方で実戦でどういうコードを書けばよいのかがわからない部分がありました。たとえばエラー処理の仕方は書いてあるのですが、実際にどのようなエラー処理を行うべきかわからない、みたいな感じです。もちろん適切なエラー処理はアプリケーションによって異なるので一概に言えないとは思いますが、たとえばCLIを題材にエラー処理の実例が紹介されていたりするとよかったのではないかと思いました。

ただ、こういう部分は「みんなのGo言語」に実践的な内容が書かれているので両方読むと良い補完関係になると言えるかもしれません。とりあえずこの2冊とネット上の情報があればGoでコードを書いていく上で困ることはそんなになさそうな気配です。

JaSST'16 Tokyoでのパネルディスカッションを記事にしていただきました

だいぶ前の話になってしまうのですが、昨年JaSST'16 Tokyoで参加させていただいたOSSの品質管理に関するパネルディスカッションの内容をPublickeyさんで記事にしていただきました。

www.publickey1.jp

power-assertの@t_wadaさんのモデレートで、Twitter4Jの@yusukeさん、Asakusa Frameworkの@apirakunさんと私の4名でお話しさせていただいたのですが、リソースが不足しがちな小規模OSSで品質を担保するには多くのユーザに使ってもらう必要があるという点は共通していたように思います。会場からの質問も含め、自分自身も参考になることが多く非常に楽しいディスカッションでした。

今回はGitBucketの立場でお話しさせていただいたのですが、Apache Software Foundationでの活動や、Webアプリケーションを開発していると避けられないセキュリティ関連の話でもいろいろと思うところがあるので、そういった話もまたどこかでできるといいなと思います。

みんなのGo言語[現場で使える実践テクニック]

簡単なコマンドラインツールはNode.jsやPython*1で書くことが多いのですが、ちょっと大きめのものだったり、他の人にも使ってもらうようなものはGoで作るのがいいのかなということでGoを触り始めました。インターネット上のドキュメントなどを参考に適当にコードを書いてみているのですが、なんとなく書けるようになってきたので以前から面白そうだなと思っていたこの本を読んでみました。*2

みんなのGo言語[現場で使える実践テクニック]

みんなのGo言語[現場で使える実践テクニック]

ちょっと勘違いしていたのですが、作りとしては書籍というよりはムックですね。冒頭に環境構築など初心者向けの記事もありますが、全体としてはすでにある程度Goに触っている人向けかなという感じです。ただ、「現場で使える実践テクニック」というサブタイトル通り、入門書などには載っていないツールやライブラリ、ベストプラクティスなど実践的なノウハウが満載されています。

個人的には第1章の環境周りとGoらしいコードの書き方、第2章のマルチプラットフォーム対応、第4章のコマンドラインツールあたりはすぐに参考になりそうですし、本格的にコードを書き始めたら第6章のテストに関する内容も役立ちそうです。3章の実践テクニックや5章のリフレクションについては実際に役立つのはもう少し上級者になってからかもしれませんが、興味深い内容で楽しく読むことができました。

完全な初心者には難しいかもしれませんが、Goを活用するためには目を通しておいて損はない一冊だと思います。

*1:AWSをいじる系はAWS SDKの都合とサーバ上で編集・実行しやすいという理由でPythonを使うことが多いです

*2:技評さんの直販サイトでPDF版を購入しました。

giter8テンプレートの作り方

giter8の復活

その昔、Scala世界にはgiter8というツールがありました。GitHub上のテンプレートプロジェクトをベースにプロジェクトを作成できるというなかなか便利なものでしたが、初期の頃はWindowsでの利用に問題があったり、Typesafe Activatorという用途がモロ被りするツールが登場したりするなどしたため、ここ数年はあまり積極的に利用されていませんでした。

時は流れて2016年、Scalaの標準的なビルドツールsbtの最新版である0.13.13でgiter8テンプレートのサポートが追加されました。sbtさえインストールしておけば、

$ sbt new scalatra/scatara-sbt.g8

のようにnewサブコマンドでgiter8テンプレートを使用してプロジェクトを作成できるようになったのです。これまでactivatorを使用してプロジェクトを作成することになっていたPlay Frameworkも今ではsbt newを使用するようになっています。

なお、現在はgiter8はオリジナルの開発者であるn8han氏からfoundweekendsというorganizationに引き継がれ開発が継続されています。オープンソースって本当に素晴らしいですね!

github.com

giter8テンプレートの作り方

ドキュメントを読めばだいたい分かると思いますので、ここでは要点だけ。

まずはgiter8テンプレートのためのテンプレートが用意されているので以下のようにしてプロジェクトを作成します。なお、giter8テンプレートのリポジトリ名は末尾が.g8になっている必要があるので注意しましょう。

$ sbt new foundweekends/giter8.g8

src/main/g8ディレクトリ以下にプロジェクトのテンプレートを配置していきます。重要なのがdefault.propertiesというファイルです。デフォルトでは以下のような内容になっています。

name=My Something Project
description=Say something about this template.

ここに定義したプロパティは各ファイルに以下のようにして埋め込むことができます。default.propertiesでデフォルト値を定義しますが、プロジェクトの作成時にユーザからの入力を受け付けることができ、入力された値で上書きされます。

organization := "$organization$"
name := "$name$"
version := "$version$"
scalaVersion := "$scala_version$"

いくつか特殊なプロパティがあります。これらはファイルに変数として埋め込むだけでなく、以下のように特殊な用途にも利用されます。

  • name: 作成されるプロジェクトのディレクトリ名としても使われます。
  • package: $package$という名前のディレクトリがあるとパッケージのディレクトリ構造に展開されます。

なお、テンプレートをsrc/main/g8ディレクトリに配置する方法とは別にルートディレクトリに直接配置するrootレイアウトという方法もあるのですが、まだ実験的な機能のようです。scalatra-scalajs.g8は試しにこのrootレイアウトで作ってみました。

テンプレートのエスケープとか

テンプレートプロジェクトを作成していると、ファイル中に含まれる$をエスケープしたいとか、ファイルごとテンプレートの対象外にしたいという場合があるかもしれません。$をエスケープというかそのまま出力するには以下のようにするのが簡単です。

$var -> $"$"$var

ファイルごとテンプレートの対象外にするにはdefault.propertiesにverbatimというプロパティを追加します。半角スペース区切りで対象外にするファイルのパターンを指定することができます。

verbatim=*.html *.js

他にもテンプレートに変数を埋め込む際に便利なフォーマッタなども用意されていますので細かい話についてはgiter8のドキュメントを見るのがよいです。

テンプレートのテスト

sbt newでは以下のようにローカルファイルのテンプレートを指定してプロジェクトを作成することができるのでこれでテンプレートが実際に動作するかをテストすることができます。

$ sbt new file:///path/to/dir/my-template.g8

また、Giter8Pluginの機能を使用して、プロジェクトの作成及びscriptted testを使ったテストができるようなので、可能であれば自動テストを作っておくとよさそうです。

まとめ

sbtで使えるようになったのでgiter8テンプレートを活用していきましょう。

GitHubでGitLFSを使ってみる

実際にGitLFSを使ってみようということでGitHubで試してみました。

まずはgit-lfsのインストールから。gitはインストール済みとします。MacならHomebrewで簡単に入れられます。

$ brew install git-lfs

適当なGitリポジトリを作成し、GitLFSを有効にします。

$ mkdir git-lfs-test
$ cd git-lfs-test/
$ git init
$ git lfs install

GitLFSで管理するファイルを指定します。

$ git lfs track *.jpg

あとは普通にファイルをコミットしてpushすれば該当のファイルが自動的にGitLFSに保存されますし、git-lfsがインストールされている環境であればcloneしたりpullしたりすると自動的にローカルにもファイルの実体がダウンロードされてくるので普通にリポジトリにコミットしてるのと同じように使うことができます。

GitHub上では普通にファイルを表示することができますが、「Stored with Git LFS」と表示されるので区別が付きます。

f:id:takezoe:20170101015857p:plain

思ったより簡単に使うことができます。大きなファイルがある場合のリポジトリの肥大化は抑えることができそうですが、実際cloneやpullするときはLFSサーバからファイルを落としてくるのでクライアント側から見るとあまり変わらないような気も…。