iDempiereにおいてSSO(Single Sign On / シングルサインオン)を実現しようと、SAMLを使って実装しました。そしてテストした所、下記のように「Illegal base64 character d」というエラーと遭遇しました。このエラーはBase64エンコーディングされたデータの中に、使ってはいけない文字がある旨のエラーメッセージです。そこで、このコンテンツでは、SAMLにおけるBase64エンコーディング処理について考えてみたいと思います。
Base64エンコーディングとは
Base64とは、「A~Z」の26文字と「a~z」の26文字、そして「0~9」の10文字に、「+」と「/」の合計64文字を使用して(※実際にはパディングとして「=」も使われる)、英数字以外の文字を扱う事の出来ない通信環境においてマルチバイト文字やバイナリーデータを扱うためのエンコード方式です。
「Illegal base64 character d」のエラー原因
「Illegal base64 character d」のエラー原因は、Base64エンコーディングされたSAMLレスポンスの中に、改行コード(\r\n)が含まれている事にありました。
ソースコードの処理としては、HttpServletRequestからSAMLResponse(SAML レスポンス)を取得し、Javaが用意してくれているBase64デコード処理のクラスを使って、デコードしている時にエラーになっていました。
改行コードに使われている"\"はBase64で使用できる文字では無いので、エラーを出力しているようです。
なぜBase64エンコーディング処理されているSAMLレスポンスに改行コード(\r\n)が含まれているか?
Base64エンコーディング処理で使用できる文字に"\"は含まれません。でも実際にSAML レスポンスの中には、改行コードが含まれていました。これはSAMLの仕様を読むと理解できます。
◆HTTP POST BindingにおけるBase64エンコーディング処理について
SAMLのBindingの仕様書saml-bindings-2.0-osにおいては、POST Bindingにおいて「Base64エンコーディングした値は、適切な長さでline-wrapしてもよい」と記載されています。
ここでline-wrapは、改行を意味しているようです(※Wikipedia:Line wrap and word wrap)。SAMLのPOST Bindingでは仕様で、Base64エンコーディングしたデータを改行する事を許可(MAY)しています。
そして、わざわざ改行しても良いと許可(MAY)しているのは、原則としては"改行しない"事を意味していると思われます。実際、私がIdP(Identity Provider)として使用していたKeyCloakでは、POST BindingにおけるSAMLレスポンスはBase64エンコーディングされていますが改行は含まれていませんでした。
なぜBase64エンコーディングしたデータを改行するのか?
繰返しますが、Base64エンコーディング処理で使用できる文字に"\"は含まれません。では、なぜわざわざBase64でエンコーディングしたデータに改行コード(\r\n)を含めるのでしょうか?
Base64でエンコーディングされたデータに改行コードが含まれていると、デコードする際に改行コードを取り除かなくてはいけませんので率直に言って手間ですし、IdP側でもBase64エンコーディングした後で改行処理を加えているはずですので、IdP側でもSP側でもシステムリソースを無駄に消費しているように思えます。
MIME(マイム) 【 Multipurpose Internet Mail Extensions 】
Base64でエンコーディングされたデータに改行コードを含めるのは、歴史的な経緯で慣習的なもののようです。電子メールで英数字以外のデータを取り扱えるようにする拡張仕様のMIMEにおいてBase64が使われており、MIMEの仕様の中ではBase64でエンコーディングしたデータを76文字毎に改行しなければならない(MAST)との事です。
Base64にエンコーディングしたデータに改行を入れるメールの仕様は、さすがに影響が大きいようで、SAMLの仕様にも影響を与えているのではないかと思いますし、世の中にある他のBase64のエンコーディング処理にも影響を与えているのではないかと思います。
RFC 4648 : The Base16, Base32, and Base64 Data Encodings
RFC4648においては、仕様で改行を加えるように定義されていない限りBase64エンコーディングされたデータの中には改行を含めてはならない(MUST NOT:禁止)とされています。
3.1. Line Feeds in Encoded Data
MIME [4] is often used as a reference for base 64 encoding. However,
MIME does not define "base 64" per se, but rather a "base 64 Content-
Transfer-Encoding" for use within MIME. As such, MIME enforces a
limit on line length of base 64-encoded data to 76 characters. MIME
inherits the encoding from Privacy Enhanced Mail (PEM) [3], stating
that it is "virtually identical"; however, PEM uses a line length of
64 characters. The MIME and PEM limits are both due to limits within
SMTP.
Implementations MUST NOT add line feeds to base-encoded data unless
the specification referring to this document explicitly directs base
encoders to add line feeds after a specific number of characters.
【ポイント】SAMLのPOST BindigにおけるSP側の処理
SAMLのPOST Bindigにおいては、Base64エンコーディングされたSAML レスポンスに改行を含めるのは許可(MAY)されていますので、SP側はBase64デコードする際には改行コードが含まれている事も想定した実装をしないといけません。
ただ個人的には、SAMLのPOST BindigにおいてBase64エンコーディングしたデータに改行を含めるのはシステムリソースを無駄に消費するだけだと思うので、IdP側にはわざわざ改行を含めるような事はして欲しくないなと思います…。
ちょっとはまったし…(T.T)
他にもはまる人はいるだろうし…(T.T)