博多南ウェブサービスのblog

博多南ウェブサービスのサービス紹介

Ubuntu 22.04 (Oracle Cloud Infrastructure) の Play Framework に http (port: 80) でアクセスしたい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Oracle Cloud Infrastructure の Ubuntu 22.04 (以下、ubuntu) 内で Play Framework 2.8.x (以下、play) を実行し、http (port: 80) で "Welcome to Play!" ページにアクセスしたときのメモです。

以下、目次

やりたいこと

ubuntu で play を実行し、http://グローバル IP にアクセスする (port: 80 でアクセスする) と、"Welcome to Play!" ページが表示される(ただし、play の待ち受けポートは 9000 の default まま)。

方針

ブラウザから ubuntu 内の play まで、http でアクセスする際、許可を与える必要があるのは以下の設定であった。

ので、以下の設定を一つずつ許可にしていく。

  • Oracle Cloud Infrastructure の ネットワーク・セキュリティ・グループ 内セキュリティイングレスルール」として、『ポート80 の許可』
  • ubuntuiptables ルール」として、『ポート80 からポート9000 へリダイレクト』、『ポート9000 のリダイレクトのリクエストのみ許可』
  • 「play 内 の AllowedHostsFilter 設定」として、『グローバルIP でのhttp リクエスト許可』

詳細

Oracle Cloud Infrastructure の ネットワーク・セキュリティ・グループ 内セキュリティイングレスルール」として、『ポート80 の許可』

default ままだと、「ネットワーク・セキュリティ・グループ」または「(設定があれば)サブネットのセキュリティリスト」には、

  • ポート22 でのSSH Remote Login イングレスルール
  • タイプ3, 4 の ICMP イングレスルール
  • すべてのプロトコル、およびすべてのポートのエグレスルール

あたりが許可されていた。

ので、「ネットワーク・セキュリティ・グループ」に『ポート80 でのTCP トラフィック イングレスルール』を追加した(参考: OracleCloudよりポート許可の追加)。

ubuntuiptables ルール」として、『ポート80 からポート9000 へリダイレクト』、『ポート9000 のリダイレクトのリクエストのみ許可』

# ポート80 からポート9000 へリダイレクト
sudo iptables -t nat -A PREROUTING -m comment --comment "for http port forward" -p tcp --dport 80 -j REDIRECT --to-port 9000
# 設定行は、ssh 用設定行の次にしとこう
INDEX_INSERT=$(sudo iptables -L --line-numbers | grep 'state NEW tcp dpt:ssh' | awk '{print $1 + 1;}')
# ポート9000 のリダイレクトのリクエストのみ許可
sudo iptables -t filter -I INPUT "$INDEX_INSERT" -p tcp --dport 9000 -m conntrack --ctstate DNAT -j ACCEPT
# iptables の設定保存
sudo netfilter-persistent save

なお、sudo netfilter-persistent reload あるいは、iptables-save を呼ぶと、iptables の filter rules が重複して登録された。 これのせい?iptables-save duplicates libvirt and ufw rules on iptables-restore with iptables-persistent

よくわからないし、対処方法も調べていないので、上では明示的にsudo netfilter-persistent reload していない。

sudo reboot 時には、保存した内容のみ登録されたので、回避方法はsudo netfilter-persistent reload しない。

「play 内 の AllowedHostsFilter 設定」として、『グローバルIP でのhttp リクエスト許可』

play.filters.hosts {
  # Allow requests to example.com, its subdomains, and localhost:9000.
  # and add Global IP (ex.: 203.0.113.0)
  allowed = [".example.com", "localhost:9000", "203.0.113.0"]

補足

  • play の待ち受けポートは 9000 の default ままとしたのは、80 を割り当てようとするとroot 権限が必要らしいので
  • 「セキュリティ・リスト」と「ネットワーク・セキュリティ・グループ」は、同じ設定を登録でき、役割も重なっている部分がある。「ネットワーク・セキュリティ・グループ」でできることは、「ネットワーク・セキュリティ・グループ」を使用することを推奨するらしい。セキュリティ・リストとネットワーク・セキュリティ・グループの比較

参考にしたところ

以上でした。

【Play Framework 2.8.x サンプル】開発環境をrun 起動時に、https および http2 でアクセス可能にしたい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.16 にて、run 起動時に、https および http2 でアクセス可能としたときのメモです。

以下、目次

前提

方針

  • ローカル環境に対して https および http2 でアクセス(ローカル開発環境の https 化 を参考)
  • openssl, keytool を使って、certificate items を jks に変換
  • sbt run -D(options) で play を実行

結果

できました play-tls-test

補足

sbt run -D(options) 実行時、以下の WARNING がでます。

WARNING: An illegal reflective access operation has occurred
WARNING: Please consider reporting this to the maintainers of scala.reflect.package$
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

そのため、Java 17 では https でアクセスできないようでした。 play 2.9 では解決するよう?

参考にしたところ

以上でした。

【Play Framework 2.8.x サンプル】Firebase Authentication を使って LINE Login したい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x にて、Firebase Authentication (LINE Login を利用した) サインインしたときのメモです。

以下、目次

前提

  • セッション管理は Firebase Authentication に任せたい
  • LINE Login は導入したい
  • Play Framework でやりたい

方針

  • LINE Login について、ログインフローは pac4j にお任せ
  • セッション管理は、Firebase Authentication の id token を利用

結果

できました firebase-auth-test

できてないところ

できましたと書きましたが、以下のところはできませんでした。

  • サインイン後、(Firebase) id token を (Service Worker が) リクエストヘッダーにのせている。LINE Login 時に LINE のプロフィールにて (Firebase User Profile を) update しているが、サインイン後すぐの (ヘッダーの) id token には update 内容が反映されない。

参考にしたところ

以上でした。

【Scalameta 4.4.x】Case object から PostgreSQL ENUM を create したい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Scalameta 4.4.x を使って、Case object から PostgreSQL ENUM の create type コマンドを作成したときのメモです。

以下、目次

やりたいこと

こんな感じの enum っぽい case object から、

import enumeratum.Enum
import enumeratum.EnumEntry

sealed trait Medal extends EnumEntry
case object Medal extends Enum[Medal] {
  case object Gold extends Medal
  case object Silver extends Medal
  case object Bronze extends Medal
  lazy val values: IndexedSeq[Medal] = findValues
}

こんな感じの sql コマンドを作成したい。

create type "medal" as enum ('Gold', 'Silver', 'Bronze');

背景

結果

Scalameta 4.4x を利用して、「case object -> sql: create type as enum 作成」した。 これにより、

「case object -> sql: create type as enum

-> (Flyway を利用して)「sql file -> DB」

-> (slick-codegen を利用して)「DB -> Case class 」

-> (root のアプリから)「Case class -> DB access

みたいなことができました。

「case object -> sql: create type as enun」の詳細

macrotest

全体像

参考にしたところ

面白かったけど関係なかったところ

GitHubこちら

以上でした。

【Play Framework 2.8.x サンプル】JSON に case object を使いたい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x にて、JSON に case object を使うときのメモです。

以下、目次

前提

こんな感じの case object を含んだ case class を、

sealed trait Color
case object Red    extends Color
case object Yellow extends Color
case object Green  extends Color

case class Origami(color: Color)

こんな感じの JSON でやりとりしたい

{
  "origami" : {
    "color" : "Red"
  }
}

方針

  • case object が増えたりしたときに、変更箇所が少ない or コンパイルエラーで変更すべき箇所を教えてくれる
  • case object のパターンマッチは残したい

結果

build.sbt

libraryDependencies += "com.beachape" %% "enumeratum" % "1.7.0",

こんな感じで、

  import enumeratum.EnumEntry
  import enumeratum.Enum

  sealed trait Color extends EnumEntry
  object Color extends Enum[Color] {
    case object Red    extends Color
    case object Yellow extends Color
    case object Green  extends Color
    lazy val values: IndexedSeq[Color] = findValues
  }

  import play.api.libs.json._

  implicit val colorWrites = new Writes[Color] {
    override def writes(color: Color): JsValue = Json.toJson(color.toString)
  }
  implicit val colorReads = new Reads[Color] {
    override def reads(json: JsValue): JsResult[Color] =
      json.asOpt[String].flatMap(Color.withNameOption(_)) match {
        case Some(color) => JsSuccess(color)
        case None        => JsError("cannot parse to Color.")
      }
  }

  case class Origami(color: Color)
  implicit val origamiFormat = Json.format[Origami]

こうなります。

scala> :paste
      val json: JsValue = Json.obj(
        "origami" -> Json.obj(
          "color" -> "Red"
        )
      )

val json: play.api.libs.json.JsValue = {"origami":{"color":"Red"}}

scala>  (json \ "origami").validate[Origami](origamiFormat).get
val res0: Origami = Origami(Red)

参考にしたところ

以上でした。

【Play Framework 2.8.x と PayPay for Developers サンプル】ウェブペイメント時の画面遷移を、PC、Mobile Device で統一したい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x と paypayopa-sdk-java 1.0.3 を使って、ウェブペイメント-即時売上時の画面遷移を、PC、Mobile Device で統一したときのメモです。

以下、目次

環境

前提

  • PC の場合、支払い画面 ⇒ リダイレクト の画面遷移は同じタブ(ブラウザ)
  • Mobile Device の場合、PayPay アプリ有りだと、支払い(アプリ)⇒ 新しいタブにリダイレクト(ブラウザ)
  • Mobile Device の場合、PayPay アプリ無しだと、支払い画面 ⇒ リダイレクト の画面遷移は同じタブ(ブラウザ)

設計

  • Mobile Device (アプリ有り)において、元のタブにリダイレクトは保証できない
  • なら、支払い時は常に新しいタブ ⇒ thanks ページにリダイレクト ⇒ 一定時間後タブを閉じるであれば、画面遷移が統一されるはず

結果

  • PC、Mobile Device ともに、「支払い ⇒ 新しいタブへのリダイレクト ⇒ 自動で閉じる」 and 「元のタブは、focus イベント ⇒ 確認画面へ遷移」と統一できた

やっててつまづいたこと

  • (javascript) addEventListener() に渡す listener は、引数を自由にとれない?
  • (javascript) setTimeout(window.close, 5000)setTimeout(window.close(), 5000) とで、addEventListener() に登録した際、動作がちがう!!
  • 支払い(アプリ)⇒ 新しいタブにリダイレクト(ブラウザ)の際、リダイレクト URL には、ポート番号が指定できない(PayPay アプリ 3.23.1 の場合)(ポート番号の区切り文字 (:) がエンコード (%3A) されて指定されるため)

参考にしたところ

GitHubこちら

以上でした。

【Play Framework 2.8.x と WSL 2 サンプル】Lan 内の mobile device から WSL 2 にアクセスしたい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x と WSL 2 をつかって、Lan 内の mobile device から WSL 2 の Play Framework http server にアクセスしたときのメモです。

以下、目次

通信のイメージ

[Mobile Device]

↑↓ TCP to (host's ip):(host open port)

[Windows (host)]

↑↓ TCP port forwarding (host port ⇔ guest's ip:port)

[Http server in WSL 2 (guest)]

やること

  • Windows (host) の Firewall に、TCP アクセスのルールを追加
  • Windows (host) の Proxy Service ? (netsh で変更されるサービスは何だろう?)に、ポートフォワードのルール追加
  • WSL 2 (guest) の Http Server (Play Framework) Filter に、アクセス可能なホスト名追加

参考にしたところ

Githubこちら

以上でした。