Orenosp User's Guide for version 0.8.5 or later Table of Contents - HTTP/HTTPS Reverse Proxy Basics - Absolute URLs in Contents - Load-Balancing HTTP/HTTPS Servers - Virtual hosts and SSL server certificate - HTTP Compression - Nimda Filters - Referer Checking - Request Policing - Access and Performance Logging - User Authentication - External Authentication Servers - Client Certificate Mapping and Authorization - IP-based Access Control - Bandwidth Control - Local File Serving for Menu Pages - Processing Order - IPv4 <-> IPv6 - Proxy-Backend Communication - Adding Arbitrary Request/Response Headers - Simple Content Rewrite - Regular Expression Based Content Rewrite - Response Headers Rewrite - Cookie Attribute Translation - Advanced Reverse Proxy Configurations - Outlook Web Access (OWA) - Interoperability Tips with IIS - Miscellaneous Parameters - SSL Client Authentication - SSL Profiles For Secure Port Forwarding (SSL Tunneling), see SSL Tunneling Guide (tunnel/ssltunnel_en.txt). はじめに 各パラメータ/オプションなどの正確な文法については/padmin/doc/ sproxy_full.txtを参照してください。 HTTP/HTTPS Reverse Proxy Basics =============================== 個別のパラメータの説明はsproxy_full.txtを参照してください。 ここではいくつか例をあげます。 例-1 外部向けポート 内部ポート web page (Orenosp) (内部httpサーバー) ---------------------------------------------------------------------------- 80 http --> 10001 http 公開 web page 443 https --> 10002 http 安全な公開 web page 8888 https --> 10009 http 管理用 web page --- sproxy.conf --- #まずリスンするエンドポイント(以降リスンポートと呼ぶ)を定義し名前を付けます # proxy_listen_name = lis-http 0.0.0.0@80 http proxy_listen_name = lis-ssl 0.0.0.0@443 https proxy_listen_name = lis-admin 0.0.0.0@8888 https #そのリスンポートで受けたリクエストをフォワードするバックエンドサーバを #指定します # proxy_pass_by = lis lis-http http://localhost:10001 proxy_pass_by = lis lis-ssl http://localhost:10002 proxy_pass_by = lis lis-admin http://localhost:10009 --- 内部web serverの設定 --- - ポート10001で公開 web pageを提供する - ポート10002で安全な公開 web pageを提供する - ポート10009で管理用 web pageを提供する - すべてのポートで、Orenospからだけリクエストを受け付けるように IP制限する。 例-2 内部httpサーバではポート番号ではなく仮想ホスト名で差別化する例 外部向けポート 内部仮想ホスト名 web page (Orenosp) (内部httpサーバー) ---------------------------------------------------------------------------- 80 http --> unsecure-pub http 公開 web page 443 https --> secure-pub http 安全な公開 web page 8888 https --> secure-admin http 管理用 web page --- sproxy.conf --- # proxy_listen_name = lis-http 0.0.0.0@80 http proxy_listen_name = lis-ssl 0.0.0.0@443 https proxy_listen_name = lis-admin 0.0.0.0@8888 https # 3つのリスンポートで受け付けたリクエストはどれも http://localhost/に # 転送します。ただし転送する際にHost:ヘッダに-hhで指定した # 仮想ホスト名を付与します。 # proxy_pass_by = lis lis-http http://localhost -hh=unsecure-pub proxy_pass_by = lis lis-ssl http://localhost -hh=secure-pub proxy_pass_by = lis lis-admin http://localhost -hh=secure-admin --- 内部web serverの設定 --- - リスンポートは80のみ。 - 仮想ホスト名 unsecure-pub で公開 web pageを提供する - 仮想ホスト名 secure-pub で安全な公開 web pageを提供する - 仮想ホスト名 secure-admin で管理用 web pageを提供する - すべての仮想ホストで、Orenospからだけリクエストを受け付けるように IP制限する。 例-3 複数の仮想ホスト名を用いてサーバを公開する。 内部サーバでも仮想ホスト名で差別化する。 外部向けポート・ホスト名 内部仮想ホスト名 web page (Orenosp) (内部httpサーバー) ---------------------------------------------------------------------------- 443 https : spub1.example.com --> secure-pub-1 http 安全な公開 web page 1 443 https : spub2.example.com --> secure-pub-2 http 安全な公開 web page 2 443 https : sadmin.example.com --> secure-admin http 管理用 web page --- sproxy.conf --- # 定義するリスンポートは一つだけ # proxy_listen_name = lis-ssl 0.0.0.0@443 https # 受け付けたリクエストの転送先を決定する際に、オリジナルリクエスト内の # Host:ヘッダーの値を参照しその値で転送先を決めます。 # ただし転送する際にHost:ヘッダに-hhで指定した仮想ホスト名を付与します。 # proxy_pass_by = vhost spub1.example.com http://localhost -hh=unsecure-pub proxy_pass_by = vhost spub2.example.com http://localhost -hh=secure-pub proxy_pass_by = vhost sadmin.example.com http://localhost -hh=secure-admin --- 内部web serverの設定 --- - リスンポートは80のみ。 - 仮想ホスト名 secure-pub-1 で安全な公開 web page 1を提供する - 仮想ホスト名 secure-pub-2 で安全な公開 web page 2を提供する - 仮想ホスト名 secure-admin で管理用 web pageを提供する - すべての仮想ホストで、Orenospからだけリクエストを受け付けるように IP制限する。 --- HTTPSでこの方法を使うときの留意点 --- "Virtual hosts and SSL server certificate"セクションを参照。 例-4 単一のホスト名を用いて複数のサーバ上に散らばるアプリケーションを公開する。 App1とApp2が以下の2つのサーバ上のそれぞれ/app1/、/app2/というパスに 存在している。 https://appserver1/app1/ Application-1 http://appserver2/app2/ Application-2 これらをhttps://mine.example.com/という単一の外部向けプロキシ経由で 公開したい。 https://mine.example.com/app1/ --> https://appserver1/app1/ https://mine.example.com/app2/ --> http://appserver2/app2/ --- sproxy.conf --- # 定義するリスンポートは一つだけ # proxy_listen_name = lis-ssl 0.0.0.0@443 https # lis-sslで受け付けたリクエストのうちパスが/app1/で始まるもの全てを # https://appserver1/app1/に転送する。 # lis-sslで受け付けたリクエストのうちパスが/app2/で始まるもの全てを # http://appserver2/app2/に転送する。 # 他の全てのリクエストはエラーとして拒否。 # proxy_pass_by = url lis-ssl://*/app1/ https://appserver1/app1/ proxy_pass_by = url lis-ssl://*/app2/ http://appserver2/app2/ --- 内部web serverの設定 --- この例のように外部向けパスと内部パスを一致させると他に設定を変える必要がない。 しかし外部向けパスと内部パスを一致させられない場合、app server側で相対パスを 使うかOrenospのコンテンツ・リライトでHTML内のパスを書き換える必要が出てくる。 例-5 Basic認証が必要なバックエンドサーバへ固定の認証情報を送る 通常、Basic認証のかかったバックエンドのページにアクセスすると Orenospはバックエンド−クライアント間でBasic認証の情報を単に通過 させます。 しかしBasic認証のかかったバックエンドに固定的な認証情報を付加して アクセスするように設定することもできます。 proxy_pass_by = lis lis-ssl http://username:password@localhost:10001 Absolute URLs in Contents ========================= Generally if a web application is put behind a reverse proxy, its contents shouldn't have absolute URLs in them. But if you already have such an application, then there are two options: 1) Contents that use $SERVER_NAME and friends to achieve site-name independence -> specify -hh="_self_" 2) Contents that have literal absolute URLs -> specify -rw_url=on (automatic URL rewriting in content) If you have an application that spans multiple web servers and has links to one another, the automatic URL rewriting (-rw_url) won't solve the problem. In this case, you need to manually configure content rewrite rules. (See Content Rewrite) Load-Balancing HTTP/HTTPS Servers ================================= With load-balancing, you can distribute HTTP request processing among multiple equivalently configured backend servers. In the basic reverse proxy mode, destinations of requests are specified as a regular HTTP or HTTPS URLs. To use multiple servers for load-balancing you will instead need to define a load-balancing group (LB group) and specify the defined LB group as the destination in proxy_pass_by rules. proxy_lbgroup_define = lbhost1 http nodes="server1,server2:8890,server3:8888" ... proxy_pass_by = vhost www.example.com lbgrp://lbhost1 -hh="..." nodes= option specifies a list of servers that will share the request processing load. A node should be specified with its hostname and an optional port number. (Note: do not specify http and https default port numbers, 80 and 443). -hh option in proxy_pass_by, if specified, applies to all the nodes in a group equally. Session Binding --------------- By default, once an HTTP session is assigned to a particular LB node, all requests from that session will go to the same LB node. This is accomplished by using an HTTP cookie ("orenosp-lbg-"). Session binding modes supported: cookie insert mode : the only one supported now other modes that may be supported in future: backend cookie mode : uses backend-supplied cookie client IP range mode : uses client IP address Load-Balancing Algorithm ------------------------ Currently Orenosp does a simple round-robin. High Availability ----------------- Orenosp proactively health-check all nodes in LB groups. In every 5 seconds, it "pings" all nodes using ICMP echo requests. If a node fails to respond to this ping request, it is considered Non-Existent (NOEX). For all other nodes that responded to pings, Orenosp sends a HTTP request: GET http-or-https://node-hostname[:port]/ If the node returns a bad status or fails to respond, it is considered Service-Down (DOWN). Otherwise, the node is considered Service-UP (UP). HTTP status codes that are considered bad are 500 (internal server error), 502 (bad gateway), 503 (service unavailable) and 504 (gateway time out). If the node's state is not UP, it is considered as dead and is temporarily evicted from its LB group. When the node's state becomes UP, it is allowed to join back to the LB group. To rephase, Orenosp does two periodic checks: (1) Ping check : all nodes (2) HTTP check : all non-NOEX nodes (DOWN and UP nodes) Apart from the peridic checks, Orenosp also retries to send the client HTTP request to another node if the first request fails. If you want to take a node into maintenance, you can just shutdown its HTTP service, shutdown the OS, or just remove the node from the network. After the maintenance, you can start the HTTP service or plug-in the network again. --- Tunables --- You can configure the HTTP check to be applied only for DOWN nodes. This way, you can avoid periodic HTTP check on UP nodes. You still get a similar level of high availability. proxy_lb_hcheck_downonly = 1 Monitoring ---------- You can configure Orenosp monitoring module and check status of LB groups. See "Monitoring Module" later in this guide. Virtual hosts and SSL server certificate ======================================== 単一のSSL listen port (IPアドレス+ポート)上で複数の仮想ホストを公開する 場合の注意点。 SSL用サーバ証明書に含まれるホスト名が仮想ホスト名と一致しなければ ブラウザはホスト名が一致しないという警告を発します。 それを避けるには以下のどちらかで証明書を作成する必要があります。 1) 複数の仮想ホスト名をサーバ証明書に登録する(subjectAltName)。 仮想ホスト1 : myweb1.example.com 仮想ホスト2 : myweb2.example.com 仮想ホスト3 : myadmin.example.com 証明書のsubjectAltName : DNS:myweb1.example.com, DNS:myweb2.example.com, DNS:admin.example.com gencertを使用する場合、"gencert -gen -1"で起動し"Do you want to put multitple DNS names?(y/n)"という質問にYと答えて myweb1.example.com, myweb2.example.com, admin.example.com と入力すればそのような証明書が作成できます。 2) ワイルドカードホスト名を証明書のCNに入力(ワイルドカード証明書) 仮想ホスト1 : www.mycompany.com 仮想ホスト2 : www2.mycompany.com 仮想ホスト3 : admin.mycompany.com 証明書のCN : *.mycompany.com HTTP Compression ================ sproxy.confの以下の行を見つけてコメントをはずします。 #proxy_filter_define = comp-txtonly mod_filt_zlib mtype="text/" #proxy_filter_assign = * comp-txtonly 上記のように設定すると、以下の全ての条件を満たしたレスポンスボディ (コンテンツ)がHTTP圧縮された形でクライアント側に送られます: - HTTPステータスが200 (HTTP_OK) - テキストファイルである(MIMEタイプ名が"text/"で始まる) - クライアント(要求側)がHTTP圧縮レスポンスを受け取れる その他のオプションに関してはOrenosvのユーザーズガイドおよびコンフィグファイル を参照してください。 http://hp.vector.co.jp/authors/VA027031/orenosv/guide_jp.txt http://hp.vector.co.jp/authors/VA027031/orenosv/http_dflt.txt Nimda Filters ============= 標準ポートの80でHTTPをリスンしているとNimda系のアクセスが飛んできます。 内部HTTPサーバにこれをフォワードせずOrenospでこれらのリクエストを処理する ことができます。 以下の設定をsproxy.confに入れます。 #--- Nimda filter BEGIN --- # --- set to 1 to enable nimda filters proxy_nimda_enable = 1 # --- nimda rules, specify path pattern --- # up to 128 rules can be specified proxy_nimda_path = /scripts/root.exe* proxy_nimda_path = /MSADC/root.exe* proxy_nimda_path = /msadc/*/winnt/system32/cmd.exe* proxy_nimda_path = /c/winnt/system32/cmd.exe* proxy_nimda_path = /d/winnt/system32/cmd.exe* proxy_nimda_path = /_vti_bin/*/winnt/system32/cmd.exe* proxy_nimda_path = /_mem_bin/*/winnt/system32/cmd.exe* proxy_nimda_path = /scripts/*/winnt/system32/cmd.exe* proxy_nimda_path = /default.ida* proxy_nimda_path = /scripts/Admin.dll #--- END --- 上記のように設定すると、 proxy_nimda_pathにマッチするリクエストはすべて Bad Requestエラーを返すようになります。そして/trash.logに マッチしたURLを書き出します。 その他にもこまごまとした動作指定できるパラメータがあります。 sproxy_full.confを参照してください。 Referer Checking (直リン禁止) ============================= Refererフィールドをnimdaフィルターでチェックすることで他のサイトからの 自サイト内の画像ファイル等への参照を制限することが可能です。 主な利用目的として「直リン禁止」があります。 「直リン」(直接リンク)とは、あるウェブページ上に存在する資源(HTMLページや 画像)へ著作権を侵害しうる形でリンクすることであるとここでは定義します。 インターネット上で問題視されている具体的な例として、画像ファイルへの 埋め込みリンクがあります。タグによりブラウザはそのリンク先の 画像をダウンロードしあたかもリンクを張っているウェブページの一部であるように ユーザに表示します。これは公正でない引用・無断複製となりえますし、さらに そのサーバの画像提供者側の貴重なネットワーク帯域を消費させてしまいます。 HTML的にはタグによるリンクは通常のリンクでなく埋め込みリンク (embedding link)として分類されています。しかしタグを使った通常リンクも タグを使えば埋め込みリンクと同様の効果が得られます。したがって 「直リン」か否かの判断は参照に使われるHTMLのタグの種類ではなく、参照を 行うウェブページの作りによって行われるべきものです。 注意: ここで定義している直接リンクは一部で主張されている「無断リンク」とは 一切関係ありません。 nimdaフィルターの規則で、Referer要件をつけることで直リンを禁止します。 proxy_nimda_path = -ref= にマッチするリクエストは、Refererフィールドを持ちかつ その値が以下とマッチすればアクセスが許可されます。そうでなければ リクエストは拒否されます: {http|https}:// つまり自サーバ上にあるにマッチする資源からのリンク でなければ、nimdaリクエストとして扱い拒否します。 ===重要=== このアクセス制限はあくまでもブラウザを使用している一般ユーザに 直リンダウンロードを禁止しているだけであり、IPアドレスやパスワードによる 厳密なアクセス制限ではありません。特殊なダウンロードソフトを使うと簡単に 回避されます。したがって、無制限公開を意図しないデータはかならず 必ずこの直リン制限とは別にパスワードなどのアクセス制限を行ってください。 ========== 例-1 /myhome配下の画像ファイルは/myhome/配下のpict*ページからしか参照させない proxy_nimda_path = /myhome/*.jpg -ref=/myhome/pict*.html proxy_nimda_path = /myhome/*.gif -ref=/myhome/pict*.html 例-2 トップページにだけ外部からのリンクを許すという制限方法を実現するには トップページ以外のファイルを全てをサブディレクトリに格納する必要があります。 ウェブページ構造 /index.html 直リン可能 /html/... 直リン禁止 /image/... 直リン禁止 proxy_nimda_path = /html/* -ref=/* proxy_nimda_path = /image/* -ref=/* Request Policing ================ Nimda filterに加えてさらにある種のHTTPリクエストを検査・拒否する設定が あります。下記を有効にするにはすべてproxy_nimda_enable=1を設定する必要が あります。 proxy_plc_max_post_datasz = POSTやWebDAV等でクライアント側から送られてくるデータのサイズを制限します。 0だと制限しません。 リクエストのContent-Sizeをチェックします。 proxy_plc_req_chunked_disable = { 0 | 1 } 1に設定するとPOSTやWebDAV等でクライアント側からchunked encoding形式で 送られてくるデータを拒否します。 リクエストのTransfer-Encodingにchunkedが含まれているかチェックします。 proxy_plc_max_url_len = 特定サイズ以上のURLをもつリクエストを拒否します。URLは'?'以降のクエリ パラメータも含みます。 proxy_plc_max_path_len = 特定サイズ以上のPATHを持つリクエストを拒否します。PATHはURLのうちクエリ パラメータを含まない部分です。 proxy_plc_url_8bit_disable = { 0 | 1 } URLに8ビット文字を含むリクエストを拒否します。日本語URLでも正しく URLエンコードされている場合は8ビット文字にはなりません。 proxy_plc_basic_auth_disable = { 0 | 1 | 2 } パスワードを平文で送るHTTP Basic Authenticationを制限します。 0: 制限なし 1: 通信路がSSLでない場合、Basic Authenticationを許しません(リクエスト・ レスポンス共に)。 2: 常にBasic Authenticationを許しません(リクエスト・レスポンス共に)。 Access and Performance Logging ============================== - Access Logging See proxy_log_access_XXX parameters in sproxy_full.txt - Performance Logging You can add request's response time access logs by specifying 0004 flag to proxy_log_access_flags. The reponse time is defined as the time in seconds from when the request is received from the client and when the proxy has finished sending the last byte of the content. You can also have another dedicated performance logging for tracking backen response times. proxy_perf_logio = single perf.log Format for performance log files time: time when the front request is received from client hmethod: HTTP verb in backend request url: request URL to backend (enclosed by "") hstatus: HTTP status from backend inbytes: bytes sent to backend (sizeof request body) outbytes: bytes received from backend (size of response body) tm_connect: (2-1) time(msec) to connect tm_sendreq: (3-2) time(msec) to send request including req body tm_waitres: (4-3) time(msec) to wait for response headers tm_recvbody (5-4) time(msec) to receive all response body As of version 0.4.2, inbytes are not yet correctly reflected in the log. - Remote Logging You can direct Orenosp to send log records to a Logging Service running on another PC. This function is applicable to the following logs: proxy_log_access_io, proxy_perf_logio, proxy_nimda_logio, proxy_htrace_logio Syntax of proxy_log_access_io: proxy_log_access_io = remote hostname:port { ssl | tcp } label hostname:port : log service's hostname and TCP port { ssl | tcp } Specify "ssl" to connect over SSL. SSL profile "cldflt" is used for the SSL operations. Specify "tcp" (or its synonym "raw") to connect over TCP. Note that logging communication including username and password will not be encrypted. label : any string that the log service requires -u=username:password : username and password to connect to the log service example proxy_log_access_io = remote host1:13000 ssl /host1/proxy \ -u=logadmin/passwd [Developing a compatible network log service] Please see remote_log_spec.txt. User Authentication =================== 内部サーバへのアクセスを認証・認可する2つの選択があります。ひとつは 全てのリクエストを通過させてバックエンドサーバ側で認証・認可を行わせます。 もうひとつはリバースプロキシにリクエストを認証・認可させることです。 クライアント(フロント)コネクション上のユーザを認証・認可する方法は3つ あります。それぞれを組み合わせることも可能です。 Passing Through Authentication to Backend ----------------------------------------- By default Orenosp will relay HTTP basic, HTTP digest and any types of cookie-based authentication/authorization requests from/to backend servers. Windows Integrated Authentication: By default Orenosp will not pass through Microsoft-proprietary HTTP authentication methods. These include MS NTLM authentication and MS Negotiate authentication. When orenosp finds response headers requesting one of these auth methods, it will silently drops that response header. See proxy_auth_disable_XXX parameters in sproxy_full.txt. Set the following parameter to enable these auth methods. proxy_auth_disable_ntlm = 0 proxy_auth_disable_negotiate = 0 Authenticating and Authorizing at Reverse Proxy ----------------------------------------------- 1) HTTPベーシック認証 (HTTP Basic authentication) This is the most simple and easy method. If your backend server also enforces HTTP Basic Authentication, it won't work because each of the reverse proxy (front-end) and the backnd will request a basic authentication. There are three options: - Use a form based authentication at the proxy. - Specify a fixed username and password in backend specifier in proxy_pass_by parameter. (uname:passwd@backend:8888). - Have the proxy to pass username and password received to the backend. The latter only works if your proxy and backend server uses the same authentication database. (You need to set "proxy_auth_pass_to_backend = 1") 2) フォームベース認証 (Form Based authentication) This is probably the most prefered method by users and server admins. フォーム・ベース認証ではカスタマイズ可能なHTMLページを使いユーザ認証が行えます。 また'orenosp-authck-XXX'という名のcookieを使用しているのでバックエンドでの HTTP基本認証やフォーム・ベース認証と共存できます。さらに受け付けたユーザ名・ パスワードをHTTP基本認証情報としてバックエンドに渡すことも可能です。 (You need to set "proxy_authck_pass_to_backend = 1") 3) SSLクライアント認証 (SSL client authentication) See section "Client Certificate Mapping and Authorization". HTTP Basic Authentication ------------------------- #proxy_auth_url = [options] proxy_auth_url = lis-ssl://*/* -u="user1:pass1" -rlm="Local Server" proxy_auth_url = lis-ssl2://*/* -u="user2:pass2" -rlm="Note Server" # [optional] pass user credential to backend's basic auth proxy_auth_pass_to_backend = 1 Form Based Authentication ------------------------- - /_formauth というディレクトリを作成 - /padmin/_formauth 内の全てのファイルを/_formauth にコピーする。 コマンドプロンプトから以下のコマンドで一発でコピーできます: > cd > xcopy padmin\_formauth _formauth\ sprox.confを編集する - Form Based Authenticationを有効にする proxy_authck_enable = 1 - [optional] # pass user credential to backend's basic auth proxy_authck_pass_to_backend = 1 - authentication type (protection realm)を定義する proxy_authck_define = noone -u="" -rlm="nobody allowed" proxy_authck_define = fmauth1 -u="user1:passwd1,user2:passwd2" \ -rlm="Restricted Area" -u でユーザ名とパスワードのリストを指定します。空のパスワードを指定すること で、外部認証サーバを使うことができます。 例: -u="user1:,user2:" (パスワードが無い場合でも':'は指定しなければ なりません)。 External Authentication Serversを参照。 -rlm ではprotection realmの名前を指定します。省略した場合、authentication typeの名前(例では"fmauth1")が使われます。 -tmo= : idle login timeout in minutes (must be >= 2) default is 30 (minutes). -ckdomain="domain-name" : specifies "domain" name in the ticket cookie. if you have two vhosts, www.example.com and www2.example.com, you could set -ckdomain=".example.com" (notice the leading dot) so that a user could be authenticated just once for all vhosts in *.example.com. - 仮想パスもしくはURL空間を定義したprotection realmにマップします proxy_authck_assign = * fmauth1 もし保護したいURL空間をvhost1だけに限定したい場合は: proxy_authck_assign = *://vhost1.example.com/* fmauth1 注意: デフォルトではどのURL空間もアクセス制限されていません。 全てのURL空間のアクセスを制限したい場合は以下のパラメータを他の proxy_authck_assignパラメータよりも__上__に配置してください: # for all others, deny any access proxy_authck_assign = * noone - OPTIONAL: add authorizatin list The protection domain defined by proxy_authck_define is really user authentication domain. For each URL space, you can specify a list of users who should be allowed access. # anyone who are successfully authenticated can access. proxy_authck_assign = *://vhost1.example.com/* fmauth1 # for /private/* space, only user "admin1" and users in "admin" group # will be allowed access. proxy_authck_assign = *://vhost1.example.com/private/* fmauth1 \ -allow="admin1,@admins" User grouping information is stored in /grpdb.txt. 保護したページをアクセスする 保護されたページをアクセスした場合、"/_formauth/login.html"ページに リダイレクトされます。 リダイレクト時にプロキシはアクセスを試みたページのprotection realmを 指定するクッキーを送ってきます。(上記例では"Restricted Area"がrealmと なります)。プロキシはこのrealm名を使ってユーザ認証を行うauthck typeを 見つけます。 注意: リダイレクトされずに直接"/_formauth/login.html"をアクセスした場合、 プロキシにはrealm名が分かりません。そのような場合は、デフォルトとして 設定ファイルで最後に定義されたauthck typeを使います。 0.4.1以前ではこのような場合認証は単に失敗していました。この動作変更は ユーザがログインページをブックマークする場合により望ましいものです。 フォームベース認証ページのカスタマイズ フォームベース認証を有効にすることで、"/_formauth/"から始まる仮想パスは: - プロキシによってインターセプトされます - __一切の認証なしで__アクセス可能になります - $ORENOSP_HOME/_formauthディレクトリのファイルが送られます したがってこのディレクトリに存在するファイルを認証ページに埋め込むことが 可能です。以下はフォームベース認証モジュールによってアクセスされる特殊な ファイル群です: /_formauth/validate : ビルトイン・パスワード確認プログラム (not customizable) /_formauth/login.html : ログインページ(HTML) /_formauth/loginerror.html : ログインエラーページ(HTML) /_formauth/loginsuccess.html : ログイン成功ページ(HTML) このディレクトリに他のHTMLファイル、アイコン、javascriptなど如何なる ファイルを置くことができます。 External Authentication Servers =============================== フォーム・ベース認証とHTTP基本認証では、ユーザパスワードを確認するための 外部認証サーバをサポートしています。user-password-listに空のパスワードを 指定することで、これら認証モジュールは指定された認証サーバに問い合わせを 送るようになります。空のパスワードは "username:" と指定します。 (':'はつけてください)。 また、"_valid_"という特殊ユーザ名を指定することにより、外部認証サーバ で認証された全てのユーザを許すこともできます。 現在のところサポートしている外部認証サーバのタイプは3つあります: - HTTP/HTTPS 基本認証サーバ ユーザ名・パスワードと共にHEADリクエストをに送ります。 ステータスとして200が帰ってくればユーザは認証されます。 実際の動作詳細: まず最初に認証情報なしでHEADリクエストを送り、指定された サーバが実際にユーザ認証を要求しているのか確認します。そうであれば、つぎに 認証情報共に新たなHEADリクエストを送り、ステータス200が返されるかを確認 します。その場合だけユーザは認証され他のケース全てでは認証は失敗します。 - ファイルベース認証 Authenticates username and password against "passwd.txt" file which usually resides in . Also, when using this methods, you can authenticate users against the OS's native authentication mechanism (os_acl option). See Users Guide for detail. - PAM認証 (Linux version only) Authenticate username and password using a PAM rule specified by "orenosp". You need to create /etc/pam.d/orenosp, possibly by copying another entry like "login" or "system-auth". HTTP認証サーバを指定するには: - Prepare a web server that requires HTTP basic authentication. Say, "https://authserver1". (You can use either http or https web server) - HTTP Basic認証を要求するWebサーバを用意します。 例えば "https://authserver1"です。(http、httpsどちらのWebサーバでも使えます) - for Form Based Authentication proxy_authck_authsrv_url = https://authserver1/ - for HTTP Basic Authentication proxy_auth_authsrv_url = https://authserver1/ ファイルベース認証サーバを指定するには: - for Form Based Authentication proxy_authck_authsrv_file = passwd.txt - for HTTP Basic Authentication proxy_auth_authsrv_file = passwd.txt PAM認証を指定するには: - for Form Based Authentication proxy_authck_authsrv_pam = svcname=orenosp - for HTTP Basic Authentication proxy_auth_authsrv_pam = svcname=orenosp Note when both parameters are present in sproxy.conf, proxy_auth_authsrv_url takes precedence. 注意: HTTP基本認証(proxy_auth_xxx)では保護されたページへのアクセスのたびに ユーザパスワードが確認されます。認証サーバへの問合せ回数を減らすために プロキシは問合せ結果をメモリ内にキャッシュします(positiveおよびnegative両方)。 これらキャッシュは3分でタイムアウトします。 Client Certificate Mapping and Authorization ============================================ You can use SSL client certificates for authenticating user certificates, and enforce access contol based on them. First you enable SSL Client Authentication, then you use Client Certificate Mapping for two purposes. 1) Authorize access based on certain certificate attributes. 2) Establish mappings between certificates and usernames which will be used in subsequent authentication/authorization mechanisms (like basic auth and form-based auth). In 1) usage, you can protect a certain URL space by restricting access to those clients who have certficates with certain attributes. Let's say you want to restrict access to clients having certificates with "O=Tange Kentou Club". Then map all clients with Tange Kentou Club to a single username "tange-club", and restrict access to that user. In 2) usage, you don't really protect URL spaces, but just specify certificate to username mapping rules for URL spaces. You also specify other authentication/authorization rules (like basic auth and/or form-based auth), which would require the client to use the mapped username. For example, if a client having a certificate with "CN=Joe Yabuki" is mapped to "jyabuki", the client will be required to use "jyabuki" as username for subsequent basic auth and/or form-based auth. Parameters used (see sproxy_full.txt for complete list of options): proxy_authcert_define = ... proxy_authcert_assign = Steps - Enable SSL Client Authentication by following "SSL Client Authentication" section. You need to set proxy_ssl_clauth to either "require" or "optional". proxy_ssl_clauth = require or proxy_ssl_clauth = optional If you choose "require" your users will need to present a valid certificate upon connecting your proxy. If they don't, an HTTPS connection will not be established. If you choose "optional" your users will not be required to present a valid certificate but offered a chance to present one upon connecting your proxy. So "option" allows both users with a certificate and without a certificate to connect. Interoperability Note: In very old browsers, using "optional" will ... - Define certificate mapping and authorization rules A) Restrict access to users with "O=Shiraki Corporation, OU=Boxing Gym" --- certmap.txt --- shiraki-boxing Subject O=Shiraki Corporation, OU=Boxing Gym --- end --- --- sproxy.conf --- # allow certificate-mapped users user1 and user2 proxy_authcert_define = shiraki -u="shiraki-boxing" -cmap=certmap.txt proxy_authcert_assign = * shiraki B) Map certificate to a username and require that username in subsequent The key option here is "-set_username=1". --- certmap.txt --- jyabuki Subject CN=Joe Yabuki, O=Tange Kentou Club tange Subject CN=Tange, O=Tange Kentou Club --- end --- # establish mapped username to be required in subquent other auths. # That is, Joe needs to log in as "jyabuki" for subsequent form-based auth, # and Tange needs to log in as "tange" for subsequent form-based auth. proxy_authcert_define = tange -u="_valid_" -set_username=1 -cmap=certmap.txt proxy_authcert_assign = * tange # use mapped username in form-based auth proxy_authck_define = ... -u="jyabuki,tange" Certificate Mapping Rules ------------------------- The default filename used for storing certificate mapping rules is /certmap.txt. You can specify a different file with -cmap= option. Modification to the specified file is monitored by Orenosp and the file is re-read as necessary. You don't have to restart Orenosp to reflect changes. Syntax : username to mapp to Subject ,,... Hash_SHA1 If you need other matching method, please request to the auther. DN-Pattern : the following attribute names are recognized: CN : Common Name O : Organization Name OU : Organization Unit Name L : Locality Name C : Country Name E : EmailAddress - the following can be used in subject DN matching only (not for issuer DN) NOT YET IMPLEMENTED altDNSName : subject alternative name - DNS name (hostname) altEmail : subject alternative name - Email address If an attribute value contains a ',', it must be prefixed by '\'. O=Shiraki Corporation\, Inc., OU=Boxing Gym certificate-fingerprint-in-SHA1-in-hex : can accept two forms ':'-separated: 57:E7:BB:5D:20:D3:61:49:B9:F1:5E:18:14:6D:43:84:85:75:88:BB ' '-separated: 57 e7 bb 5d 20 d3 61 49 b9 f1 5e 18 14 6d 43 84 85 75 88 bb IP-based Access Control ======================= IP-based Access Control can be enforced in two ways: - per connection basis (specified in proxy_listen_name) - per request basis (specified by proxy_authip_url) Per-connection access control is more effective because it checks client's IP before establishing an SSL / HTTP connection, thereby thwarting SSL handshake DoS attacks. Per-request access control gives you more flexibility by giving finer control over URL space that a user is allowed to access. Both methods can use either the same access control list or separate ones. That is, you can specify a text-based IP pattern file to both modules. The IP pattern file can be edited while the service is running. Orenosp will detects file modification and reloads patterns from the file. There's no limit on the number of IP patterns in a file. --- a sample IP pattern file --- # you can comment out a line with '#' 123.123.0.0/16 123.234.0.0/16 234.123.123.128 --- end --- Refer to sproxy_full.txt for more details - "ip_allow/ip_deny/ip_order" options in proxy_listen_name - "IP-based Access Authorization" (proxy_authip_url) Bandwidth Control (Throttling) ============================== See sproxy_full.txt for actual parameters. IMPORTANT : current limitations - Only the SEND direction (reverse proxy sending out contents) is currently supported. - BW control works over data that have not been processed by output filters. This means that the amount of data that's subjected to the bandwidth control will differ from the actual amount of data that goes over the wire. For example, if the HTTP compression filter reduces a 1MB content by 90%, the bandwidth control will see it as 1MB of data even though only the 100KB of data is actually sent over the wire. A work around would be to let the backend server to compress the contents and let them through the reverse proxy. Of course, it won't be possible to rewrite contents with this way. Local File Serving for Menu Pages ================================= プロキシ経由で複数のサーバ・サービスを公開している場合、「メニューページ」 のようなものが欲しくなります。通常はバックエンドサーバの一つでそのような メニューページをホストすればよいのですが、それが不可能な場合もあります。 (例えば全てのバックエンドはデバイスのような場合)。 そのような状況のために、Orenospは簡単なローカルファイルサーブ機能を 持っています。 proxy_lfile_enable = 1 を設定すると、/_intmenu/配下の全てのファイルがURL /_intmenu/XXX でアクセス可能になります。これらファイルへのリクエストは通常の認証・認可 の対象になることに注意してください。つまりベーシック認証やフォームベース認証 でチェックされます。 さらにトップページからメニューページにユーザを導くためにトップURL("/")を "/_intmenu/menu.html"にリダイレクトするように設定しておくとよいでしょう。 # "/" を /_intmenu/menu.html にリダイレクトする ("-s" オプションに注意) proxy_redirect_by = url lis-ssl://host.com/ https://host.com/_intmenu/menu.html -s Processing Order ================ - [On connect only] Per-Connection IP-based Access Control - Request policing (proxy_plc_xxx) - Check for nimda requests - Per-Request IP-based Access Control - Certificate Mapping and Authorization - Redirect if matched with proxy_redirect_by - Simple basic authentication - Form based authentication - Switch to tunneling if SSLVPN - Redirect if matched with proxy_redirect_by (when "-2" is used) - Serve local files if "/_intmenu/xxx" - Serve monitoring request - Reverse-proxy request to backend if matched with proxy_pass_by IPv4 <-> IPv6 ============= IPv6を使うにはIPv6対応別バイナリのOrenospが必要です。(orenospXXXi6.exe) Limitations in the Current Release ---------------------------------- These will be addressed in future release as demand for IPv6 grows. - SSL Portforwarding over IPv6 is not supported Especially, tnapplet (Java) is not IPv6-enabled. Other components may work but not tested yet. - Load-Balancing to IPv6 backend servers is not supported This is because the load-balancing feature requires ping (ICMPv6) functionality but it is not quite implemented yet. IPv4-LAN内のHTTPサーバをIPv6のネットワークに公開する ---------------------------------------------------- # proxy_listen_name = lis-ipv6 ::@80 http # proxy_pass_by = lis lis-ipv6 127.0.0.1 IPv6-LAN内のHTTPサーバをIPv4のネットワークに公開する ---------------------------------------------------- # proxy_listen_name = lis-ipv4 0.0.0.0@80 http # proxy_pass_by = lis lis-ipv4 [::1] -hh=127.0.0.1 []という表記は、URLのホスト部にIPv6アドレスを指定する際に 使用されるものです。 URL表記 Orenosp http://[fe80::203:2fff:fe02:c640]/ -> [fe80::203:2fff:fe02:c640] http://[fe80::203:2fff:fe02:c640]:81/ -> [fe80::203:2fff:fe02:c640]:81 名前解決 - DNSの設定について ---------------------------- IPv6サーバをIPv4ネットワークに公開する場合 DNSエントリ IPアドレス(A) host1.mycompany.com host2.mycompany.com と設定し、Orenospで仮想ホスト名でリクエストを振り分けます。 IPv4サーバをIPv6ネットワークに公開する場合 DNSエントリ IPアドレス(AAAA) host1.mycompany.com host2.mycompany.com と設定し、Orenospで仮想ホスト名でリクエストを振り分けます。 IPv6,v4どちらからでもリクエストを受け付けたい場合 host1.mycompany.com A host1.mycompany.com AAAA host2.mycompany.com A host2.mycompany.com AAAA また逆引き用にIPv6アドレスのPTRレコードも記述しなければならないが、 ここでは省略する。 その他 ------ - Note about "localhost" When you install IPv6 stack on Windows XP or Windows 2003, it seems like that the first IP address that the OS returns for "localhost" is IPv6 loop back address (::1), not IPv4 loop back address (127.0.0.1), even though "127.0.0.1 localhost" is in etc/hosts file. You can try "ping localhost" to see which address it's pinging. This will cause many problems including Orenosv. Use 127.0.0.1 instead of "localhost" whenever you have a strange problem. - link-localアドレスをlistenポートとして指定する場合は、 scope-idとしてinterface numberを追加してください # in case of IPv6 link-local address, append interface number # following '%'. proxy_listen_name = lis-ipv6 fe80::203:2fff:fe02:c640%3@8888 http # ^^ interface numberはつきのどちらかのコマンドで取得できます。 >ipv6 if (XP SP0) >netsh ??? (XP SP1 or higher, Win2003) - link-localアドレスをconnectアドレス(URL)として指定する場合は、 interface numberを指定してはいけません。 [fe80::203:2fff:fe02:c640%3]:81 ^^ DON'T DO THIS Proxy-Backend Communication =========================== Passing Client IP Addresses to Backend Servers ---------------------------------------------- Many HTTP reverse proxies including Orenosp will add the following headers to client request: X-Forwarded-For: X-Forwarded-Host: X-Forwarded-Proto: <"http"-or-"https"-of-client-request> If you are using Apache as a backend server, you can use a module called "mod_rpaf" to make the Apache server to 1) accept X-Forwarded-For:'s IP address as real client's IP address, 2) accept X-Forwarded-Host:'s value as real virtual hostname. X-Forwarded-Proto header is introduced in Orenosp 0.7.4c and Orenosp-specific. Adding Arbitrary Request/Response Headers ========================================= リバースプロキシ時に任意のHTTPヘッダをリクエストやレスポンスに付加する ことができます。proxy_pass_by パラメータの"-rq_hdr"と"-rs_hdr"を使用します。 -rq_hdr : リクエストヘッダを追加 クライアント ---> Orenosp ---> バックエンド ココ -rs_hdr : レスポンスヘッダを追加 クライアント <--- Orenosp <--- バックエンド ココ Simple Content Rewrite ====================== If you use any reverse-proxy, you can no longer use "absolute URLs" that point to pages on the same reverse-proxied server. For example, let's say "https://www.mine.com/" is reverse-proxied to "http://internal1/" and if you write an HTML link as then, users on the Internet try to go to the internal server directly, which fails. You need to rewrite the URL as "https://www.mine.com/doc/abc.html". Orenosp and Orenosv have a mechanism to do this kind of content (response-body) rewriting. mod_filt_rwt (optimized rewrite filter) implements this content rewriting functionality. It has two sub-modules, one is simle text search-and-replace filter, the other is a regular expression-based filter. How to configure content rewrite -------------------------------- - create a config file named /rewrite_simple.conf - add rewrite rules to the config file: ---rewrite_simple.conf--- = this is a comment http://internal1/=https://www.mine.com/ http://internal2/=https://www2.mine.com/ = eof ---end of rewrite_simple.conf--- Note on format of rewrite_simple.conf: - '=' is used as the separater: = - leading '=' (i.e., empty ) designates that line as a comment. - two consective '=' ("==") specifies a literal '='. This applies only to . - add the following line to sproxy.conf: # Content Rewrite - must come after HTTP compression filter in config file proxy_filter_define = rewrite-simple mod_filt_rwt rwtype=simple mtype="text/html" proxy_filter_assign = * rewrite-simple - restart Orenosp and check event.log Different rewrite rules for multiple paths ------------------------------------------ - use "-cf=" submodule-specific parameter to specify an alternate rewrite rule file. Note that "--" designates the begining of submodule-specific parameters. example: proxy_filter_define = rewrite-simple-1 mod_filt_rwt rwtype=simple \ mtype="text/html" -- -cf=rewrite-1.conf proxy_filter_define = rewrite-simple-2 mod_filt_rwt rwtype=simple \ mtype="text/html" -- -cf=rewrite-2.conf proxy_filter_assign = /vpath-1/* ext-rewrite-1 proxy_filter_assign = /vpath-2/* ext-rewrite-2 Trouble shooting ---------------- - Rewrites not working when called from browsers, but they work if I directly call the server with "telnet" command. -> Most likely your backend server is applying HTTP compression to the content. Orenosp doesn't decompress already compressed documents in order to apply filters. Make sure you do not apply HTTP compression to those contents. Since 0.4.3c, you can set "proxy_origin_gzip_disable = 1" to disable backend's HTTP compression. You should let Orenosp handle HTTP compression instead. Note: Orenosp can handle chunked-encoded response from a backend and "de-chunk" it. - If an HTML line are longer than 30KB bytes, the rewrite filter splits it in multiple chunks that are smaller than 30KB and work on each of them. If the string you want to rewrite happens to be in the middle of that split, the rewrite won't work. -> Make sure your HTML lines are less than 30K bytes. - Enabling trace : Setting rewrite trace level to 2 or 3 may help. (event.log will be very messy!) proxy_filter_define = rewrite-regex mod_filt_ext int=rewrite_regex \ mtype="text/html" -- -cf=rewrite-2.conf -trc=2 Regular Expression Based Content Rewrite ======================================== The configuration is basically very similar to that of Simple Content Rewrite. Refer to the above section for more info. - create a config file named /rewrite_regex.conf - add rewrite rules to the config file: --- rewrite_regex.conf --- = Header (]*>)=$1

Header Something

= Footer ()=

Footer Something

$1 --- end of rewrite_regex.conf --- Note on format of rewrite_regex.conf: - '=' is used as the separater: = - leading '=' (i.e., empty ) designates that line as a comment. - two consective '=' ("==") specifies a literal '='. This applies only to . - regex substitutions ($0,$1,...,$9) can be used in . - add the following line to sproxy.conf: # Content Rewrite - must come after HTTP compression filter in config file proxy_filter_define = rewrite-rex mod_filt_rwt rwtype=regex mtype="text/html" proxy_filter_assign = * rewrite-rex - restart Orenosp and check event.log About regular expressions The regular expression library used in this submodule is PCRE(Perl Compatible Regular Expressions). For RE rules in PCRE, see http://www.pcre.org/pcre.txt (look for "PCRE REGULAR EXPRESSION DETAILS"). Response Headers Rewrite ======================== You can rewrite many reverse-proxied response headers using the rewrite filters. example-1 # Response headers rewrite (no body rewrite) proxy_filter_define = hdr-rewrite mod_filt_rwt rwtype=simple \ headers="Server" flags=0002 proxy_filter_assign = * hdr-rewrite example-2 # Rewrite both body and headers # (rewrite both content and redirect headers (Location field)) proxy_filter_define = all-rewrite mod_filt_rwt rwtype=simple \ mtype="text/" headers="Location,Content-Location" \ flags=0007 proxy_filter_assign = * all-rewrite The proxy passes the following form of line to the filter submodule: : You can only rewrite header-values, not header-names. --- meaning of flags --- 0001 /* process response body */ 0002 /* process response headers */ 0004 /* process headers regardless of mime types */ The default flag value is 0001 (process response body only). Cookie Attribute Translation ============================ You can rewrite path= attribute in Set-Cookie: response header. See sproxy_full.txt (-ck_path option). By default domain= attribute in Set-Cookie header is dropped. You can use -ck_dom option to replace a value in domain= field with another domain. Advanced Reverse Proxy Configurations ===================================== Cookie-based Reverse Proxying ----------------------------- Example Let's say you have a large web mail system. The system is comprised of 4 servers. - login server http://login.internal/ - mail1 server http://mail1.internal/ - mail2 server http://mail2.internal/ - mail3 server http://mail2.internal/ A user first logs into the login server and the login server authenticates the user and redirects him to one of the three mail servers. The login server knows users and their designated mail servers. The assignment rule is fixed. In your intranet, you have no problem about users accessing multiple internal servers (login server -> mailN servers). However, on the extranet you want to have a single virtual server http://mail.example.com/ to handle all requests. You want to have the following rules: For user group A: https://mail.example.com/email/ -> http://login.internal/ (before login) http://mail1.internal/ (after login) For user group B: https://mail.example.com/email/ -> http://login.internal/ (before login) http://mail2.internal/ (after login) For user group C: https://mail.example.com/email/ -> http://login.internal/ (before login) http://mail3.internal/ (after login) To accomplish this, you can use "pass by cookie" sub-rule when defining pass rules. 1) First, modify the login server to issue a cookie EMAILGRP=A for group A, B for group B, and C for group C upon successful user authentication. 2) Add the following rules proxy_pass_by = url https://mail.example.com/email/ http://login.internal/ proxy_pass_by = url https://mail.example.com/email/ http://mail1.internal/ \ -pass_by_ck="EMAILGRP=A" proxy_pass_by = url https://mail.example.com/email/ http://mail2.internal/ \ -pass_by_ck="EMAILGRP=B" proxy_pass_by = url https://mail.example.com/email/ http://mail3.internal/ \ -pass_by_ck="EMAILGRP=C" When a user first access https://mail.example.com/email/, he doesn't have EMAILGRP=X cookie, so he's reverse-proxied to the login server. After successful authentication at the login server, he gets a cookie EMAILGRP=B. From then on, the user's request will always reverse-proxied to http://mail2.internal server. Outlook Web Access (OWA) ======================== The whole purpose of using Orenosp in front of OWA is to avoid exposing the IIS or the machine itself to the Internet. Plus, you get an extra layer of authentication/authorization, request filtering, unified logging and all other features of Orenosp. As for SSL usage, client-to-Orenosp connection is assumed to use HTTPS. For Orenosp-to-OWA connection, you can use either HTTP or HTTPS (SSL bridging). This documentation is based on OWA included in Exchange Server 2003 (i.e., OWA 2003). Many of it should be applicable to OWA of Exchange Server 2000 product (OWA 2000) also. Quick Configurations -------------------- There are sample configuration files for OWA as described in this section. Copy /padmin/doc/sproxy_owa_X.txt as /sproxy.conf. Four sample configurations. All of them assume the following info: Internal OWA server (front-end Exchange server) hostname: exchserver External URL https://mail.company.com/ a) SSL Bridging and OWA Form Auth - OWA 2003 only Use HTTPS (SSL) for Orenosp-to-OWA (SSL bridging). OWA uses Forms Based Authentication. No access control at Orenosp level. You can add basic, form-based and/or IP-based access at Orenosp independently. b) SSL Bridging and Orenosp Form Auth - OWA 2000 and OWA 2003 Use HTTPS (SSL) for Orenosp-to-OWA (SSL bridging). OWA uses Basic Authentication. Orenosp will use its form-based authentication and pass to OWA the user's credential as that of the OWA's Basic Authentication This way, a user will only see a single log in page. c) HTTPS->HTTP and OWA Form Auth - OWA 2003 only Use HTTP for Orenosp-to-OWA. OWA uses Forms Based Authentication. No access control at Orenosp level. You can add basic, form-based and/or IP-based access at Orenosp independently. d) HTTPS->HTTP and Orenosp Form Auth - OWA 2000 and OWA 2003 Use HTTP for Orenosp-to-OWA. OWA uses Basic Authentication. Orenosp will use its form-based authentication and pass to OWA the user's credential as that of the OWA's Basic Authentication This way, a user will only see a single log in page. Instructions for a) 1) Configure SSL and OWA Forms Based Authentication per Exchange documentations. Tip: See "Instructions for creating a server certificate for IIS very quick" 2) Use /padmin/doc/sproxy_owa_a.txt as sproxy.conf You should now be able to log in using OWA Forms Login either on direct HTTPS connection or HTTPS via Orenosp. Instructions for b) 1) Configure SSL and OWA Basic Authentication per Exchange documentations. Tip: See "Instructions for creating a server certificate for IIS very quick" 2) Use /padmin/doc/sproxy_owa_b.txt as sproxy.conf 3) Configure Orenosp form-based authentication by following "Instructions for setting up Orenosp form-based authentication" below. You should now be able to log in using Orenosp Form Login on HTTPS via Orenosp. Instructions for c) 1) Apply the following change into your Windows server's registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSExchangeWEB\OWA Value name: AllowRetailHTTPAuth Value type: DWORD Data value: 1 Then, restart the whole OS. 2) Configure OWA Forms Based Authentication per Exchange documentations. Ignore Exchange Server Manager's instruction to configure SSL. 3) Use /padmin/doc/sproxy_owa_c.txt as sproxy.conf You should now be able to log in using OWA Forms Login either on direct HTTP (not SSL) connection or HTTPS via Orenosp. If you need to disable HTTP(non-SSL) access to the OWA Forms Login, use "SSLOffload" registry key instead of "AllowRetailHTTPAuth". Instructions for d) 1) Configure OWA Basic Authentication per Exchange documentations. 2) Use /padmin/doc/sproxy_owa_d.txt as sproxy.conf 3) Configure Orenosp form-based authentication by following "Instructions for setting up Orenosp form-based authentication" below. You should now be able to log in using Orenosp Form Login on HTTPS via Orenosp. Instructions for setting up Orenosp form-based authentication Orenosp will use IIS on the OWA server (or any other computer in the same domain) as its backend authentication service. - Create a virtual directory "orenosp_auth" in the default website on exchserver's IIS. You can use any filesystem path for this. An example is c:\InetPub\wwwroot\orenosp_auth. Make the directory "readable" and "browsable". - Directory Security: disable "anonymous access" and enable "Basic authentication". ("Integrated Windows authentication" can be left enabled.) Domain and Realm can be anything. - Using IE brower, do test - whether the following URL requires basic authentication - whether you can access the URL by providing a correct credential http://exchserver/orenosp_auth/ or if you intend to use SSL https://exchserver/orenosp_auth/ You will control access to Orenosp by modifying NTFS permissions on "c:\InetPub\wwwroot\orenosp_auth". - Modify Orenosp's sproxy.conf proxy_authck_authsrv_url = http://exchserver/orenosp_auth/ or proxy_authck_authsrv_url = https://exchserver/orenosp_auth/ - Create /_formauth directory (if you haven't done so) > cd > xcopy padmin\_formauth _formauth\ Instructions for creating a server certificate for IIS very quick You can create a server certificate for IIS using Orenosp-gencert program. - Create a server certificate with gencert. gencert creates a p12 certificate pack as /myca/pfxXXX.p12. - From IIS manager's Server Certificate Wizard, just import this p12 file (p12 and pfx are same format). That's it! Instructions for manually configure a rewrite filter for Public folder This procedure must be followed if you are using OWA 2000 and the OWA public folder is not accessible via Orenosp. - create a config file named /rewrite_simple.conf - add rewrite rules to the config file: --- rewrite_simple.conf --- https://exchserver/public=https://mail.company.com/public http://exchserver/public=https://mail.company.com/public https://exchserver/Public=https://mail.company.com/Public http://exchserver/Public=https://mail.company.com/Public --- end --- Make sure the command "hostname" returns "exchserver" on your Exchange server's command prompt. - add the following to sproxy.conf --- sproxy.conf --- # Manual Rewrite Filter - must come after HTTP compression filter in config file proxy_filter_define = rewrite-simple mod_filt_rwt rwtype=simple mtype="text/html" proxy_filter_assign = * rewrite-simple --- end --- Basics ------ The safest way to make OWA available via a reverse proxy is to not touch the URL, i.e., use exactly the same external URL as the internal URL. In other words, the reverse proxy and the OWA server should (1) use the same host header (2) use the same protocol (https) (3) use the same path (i.e., don't try to translate any path) As for (1) you can specify -hh="_self_" option to proxy_pass_by rules. OWA should be installed in the "Default Web Site" with no optional host header. As for (2), you can just configure OWA to use SSL also. That is, you will use Orenosp for SSL bridging: ===SSL(1)== ===SSL(2)=== For some reason if you want to use HTTP between Orenosp and OWA, you can work around the issue using a special request header (Front-end-HTTPS:ON) proxy_pass_by = ... \ -hh="_self_" -rq_hdr="Front-end-HTTPS:ON" If you are using Forms Based Authentication in OWA 2003, you also need to set a special registry key (AllowRetailHTTPAuth=1) or set another key (SSLOffloaded=1). As for (3), there's no workaround. You need to follow this rule. Example Internal OWA URL http://exchserver/ but it can accept OWA requests on any host headers External OWA URL https://mail.company.com/ # --- listen port --- proxy_listen_name = ls-https 0.0.0.0@443 https # --- pass rules --- proxy_pass_by = url ls-https://mail.company.com/exchange \ http://exchserver/exchange -hh="_self_" -rq_hdr="Front-end-HTTPS:ON" proxy_pass_by = url ls-https://mail.company.com/ExchWeb \ http://exchserver/ExchWeb -hh="_self_" -rq_hdr="Front-end-HTTPS:ON" proxy_pass_by = url ls-https://mail.company.com/Public \ http://exchserver/Public -hh="_self_" -rq_hdr="Front-end-HTTPS:ON" # --- misc parameters required --- # this needs to be set to 0 when using "Front-end-HTTPS:ON" proxy_rewrite_destination = 0 Note that we wish to publish only OWA-related virtual directories. You may also add redirect rules to redirect users who visit "/" path to "/exchange" path. # --- redirects --- proxy_redirect_by = url ls-https://mail.company.com/ \ https://mail.company.com/exchange -s # if you also use port 80 for Orenosp: #proxy_redirect_by = url ls-http://mail.company.com/ \ #https://mail.company.com/exchange -s OWA's use of WebDAV ------------------- If you use IE to access OWA 2003, OWA will make the browser use WebDAV protocol in addition to regular HTTP/HTML. If you leave the URLs intact as indicated in the above, Orenosp should be able to successfully reverse proxy OWA's WebDAV protocol. If you observe strange behavior of OWA when using IE, see if the same behavior will happen also with other browsers (like Firefox), in which case the OWA will not use any WebDAV methods. Note: if you are using either "Front-end-HTTPS:ON" or "SSLOffloaded", you should NOT use "-rw_dav=1" option to proxy_pass_by paramter. Alternative Reverse Proxy Configuration --------------------------------------- If you cannot afford to use the same url for the internal and external names, you can try enabling automatic rewriting of contents and WebDAV requests. Internal OWA URL http://xcserver.us.company.com/ External OWA URL https://mail.company.com/ # --- Pass rules --- proxy_pass_by = url ls-https://mail.company.com/exchange \ http://xcserver.us.company.com/exchange -rw_dav=1 -rw_url=1 proxy_pass_by = url ls-https://mail.company.com/ExchWeb \ http://xcserver.us.company.com/ExchWeb -rw_dav=1 -rw_url=1 proxy_pass_by = url ls-https://mail.company.com/Public \ http://xcserver.us.company.com/Public -rw_dav=1 -rw_url=1 # --- Misc parameters required --- # this needs to be set to 1 when using automatic rewrite proxy_rewrite_destination = 1 # you may want to increase this parameter #proxy_post_save_limit = 65536 User Authentication and Authorization ------------------------------------- OWA 2000 Requires ues of either NTLM(Windows-integrated) or Basic authentications. OWA 2003 In addition to Windows-integrated and Basic authentications, it can also use its own form-based authentication. The safest choice is to use Orenosp's form-based authentication plus OWA's basic authentication. Possible combination Reverse Proxy OWA Usable on ----------------------------------------------- Orenosp-form OWA-basic OWA2000/2003 Orenosp-basic OWA-basic OWA2000/2003 (* limited. see below) Orenosp-form OWA-form OWA2003 Orenosp-basic OWA-form OWA2003 If you are using Orenosp solely for reverse proxying an OWA, welcoming end users with double authentication requests may not be desirable. Since Orenosp 0.7.2, the proxy is able to pass user credential obtained for Orenosp-form or Orenosp-basic to backend's basic authentication system. Orenosp-form -> OWA-basic : doable (proxy_authck_pass_to_backend = 1) Orenosp-basic -> OWA-basic : doable (proxy_auth_pass_to_backend = 1) Orenosp-form -> OWA-form : not doable Orenosp-basic -> OWA-form : not doable Recommendation - Use the form-based authentication at Orenosp For authentication database choise, either - use Windows user database (proxy_authck_authsrv_url = ) - use independent database (proxy_authck_authsrv_file = passwd.txt) - If OWA2000, use Basic authentication. If Orenosp and OWA share the authentication database (i.e., Orenosp uses Windows user database), you can pass user credentials to the OWA. - With OWA2003, use Basic authentication only if you want your users to avoid authenticating twice. Let user credentials pass through. Othersise use OWA forms-based authentication, forcing users to authenticate at both Orenosp and OWA. Example - Prepare Orenosp form-based authentication For backend authentication service, use localhost's IIS. Steps: - Create a virtual directory "orenosp_auth" in the default website. You can use any filesystem path for this. An example is c:\InetPub\wwwroot\orenosp_auth. Make the directory "readable" and "browsable". - Directory Security: disable "anonymous access" and enable "Basic authentication". ("Integrated Windows authentication" can be left enabled.) Domain and Realm can be anything. - Configure Orenosp form-base auth to pass user credential to the OWA Basic authentication. Orenosp passes the user credential obtained for its form-based authentication to OWA's basic authentication system. proxy_authck_enable = 1 proxy_authck_pass_to_backend = 1 proxy_authck_define = noone -u="" -rlm="nobody allowed" proxy_authck_define = anyname -u="_valid_:" -rlm="anyname" proxy_authck_assign = * noone proxy_authck_assign = ls-https://mail.company.com/* anyname proxy_authck_authsrv_url = http://localhost/orenosp_auth/ About Logging Out ----------------- Clicking OWA logout clears away all user credentials on the browser if the browser is IE6 (SP1). If you are using IE6 SP1 or later, when you click the logout button of OWA, the browser will clear HTTP basic authentication information in the browser. This is done by a javascript code that calls "ClearAuthenticationCache". On top of this, the script also seems to clear out SSL client certificate information by calling "mimeLogoff.Logoff()". We also noticed this OWA logoff page also seems clear out all HTTP cookies for the host, including Orenosp's cookie for form-based authentication. This means that it will clear out all other cookies also, like those used in load-balancing, etc. Multiple OWA Servers -------------------- Is it possible to aggregate multiple OWA servers into a single virtual host? Case 1: Two front-end Exchange Servers(OWA servers), sharing the same back-end Exchange server. exc-front-1 exc-front-2 In this case you can use Orenosp's load balancing groups (LBgroup). proxy_lbgroup_define = lbexchange nodes="exc-front-1,exc-front-2" proxy_pass_by = url https://mail.company.com/exchange lbgrp://lbexchange/exchange -hh="_self_" -rq_hdr="Front-end-HTTPS:ON" # repeat the same for /ExchWeb and /Public Case 2: Two independent Exchange Servers xcserver-tokyo xcserver-osaka It is possible to do this if you prepare a "login" server and use Orenosp's "pass by cookie" sub-rule. References ---------- http://support.microsoft.com/default.aspx?scid=kb;en-us;307347 http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=AFAD8426-572E-40F8-99DA-EB7198F374C4 Windows SharePoint Services (WSS) ================================= Reverse-proxying WSS is very similar to that of OWA. Basically you need to keep the URL unchanged between the reverse proxy and the IIS server. One significant difference is that WSS doesn't support the special "Front-end-HTTPS:ON" request header. So you must configure SSL on the IIS server and forward all requests in HTTPS protocol. References http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/sharepoint/revproxy.mspx Interoperability Tips with IIS ============================== Co-existing Orenosp with IIS on a Single Server --------------------------------------------------- - By default, IIS 5.0 (Windows 2000) binds to 0.0.0.0:80 and 0.0.0.0:443 even if SSL is not enabled on the IIS. Therefore if HTTP-only IIS is already running, Orenosp will not be able to bind to port 443. To allow IIS to use port 80 and Orenosp to use port 443, you must disable IIS socket pooling. See next subsection. - IIS 6.0 has an identical problem, but you need take a different action. See the subsection for IIS 6.0 below. IIS 5.0 (on Windows 2000) ------------------------- You need to disable "socket pooling" feature of IIS. With this feature on (default), IIS 5.0 listens on all IP addresses regardless of whether they have been assigned to IIS or not. Disabling socket pooling AND assigning unique IP addresses to IIS' sites will solve the problem. 1) Assign an IP address to a IIS web site. 2) Disable socket pooling feature of the IIS web site. > cd \inetpub\AdminScripts > cscript adsutil.vbs set w3svc/disablesocketpooling true The command prompt returns the following: disablesocketpooling : (BOOLEAN) TRUE 3) Restart the Windows (or IIS only) See MS KB 259349 IIS Binds To All Available IP Addresses When It Starts See MS KB 238131 How to Disable Socket Pooling IIS 6.0 (on Windows 2003) ------------------------- IIS binds to all IP addresses on the server, not just the IP addresses that are assigned to Web sites. Setting DisableSocketPooling to True as done in IIS 5 is not effective. You can specify IP address(es) IIS should listen on using a MS-provided support program, httpcfg.exe. Httpcfg.exe is located on the Windows Server 2003 CD in the Support\Tools directory as part of the Support.cab file. You can specify the IP addresses IIS will listen on by adding them to the IP inclusion list. Don't add the IP address that your Orenosp will use. The IP inclusion list is read during startup of the IIS HTTP service. If you change the list, you must restart the service. To add an IP address to the IP inclusion list: Type the following, where xxx.xxx.x.x is the IP address you want to add: > httpcfg set iplisten -i xxx.xxx.x.x For example, > httpcfg set iplisten -i 192.168.1.100 When this succeeds, Httpcfg returns the following: HttpSetServiceConfiguration completed with 0 After the IP address is added, use the following command to list it: > httpcfg query iplisten Httpcfg returns the following: IP :192.168.1.100 See MS KB 813368 IIS 6.0: Setting Metabase Property DisableSocketPooling Has No Effect Interoperating with IIS Windows Integrated Authentication --------------------------------------------------------- By default, Orenosp will disable Windows Integerated Authentication. Specifically, Orenosp will drop any authentication requests from backend that specify either "NTLM" or "Negotiate" methods. If you set the following parameter in sproxy.conf, Orenosp will relay these authentication methods: proxy_auth_disable_ntlm = 0 proxy_auth_disable_negotiate = 0 Please refer to "Passing Backend Authentication" in Users' Guide for more info. - Reverse-proxying IIS WebDAV See padmin/doc/webdav_en.txt. Miscellaneous Parameters ======================== proxy_origin_http11 = { 0 | 1 } オリジンサーバとの通信にHTTP/1.1を使用する。デフォルトは1でHTTP/1.1 を使用します。 オリジンサーバが動的コンテンツを送り出すとき、HTTP/1.0ではkeep-aliveが 有効になりません。HTTP/1.1を指定することでオリジンサーバは動的コンテンツを chunked encodingで送り出すことができ接続がkeep-aliveされるようになります。 その他についてはsproxy_full.txt参照。 HTTP Keep-Aliveについて http://support.microsoft.com/default.aspx?scid=http://www.microsoft.com/japan/support/kb/articles/JP305/2/17.asp SSL Client Authentication ========================= このセクションはOrenospとOrenosv FTPで共通になっています。 下で と表記されているところは、Orenospの場合 sproxy、 Orenosv FTPの場合 ftp と読み替えてください。 SSL通信ではサーバ側がクライアント側を認証する手段としてクライアント側の 電子証明書をサーバが確認するというクライアント認証というものがあります。 必要なもの クライアント側: 保護されたウェブページをアクセスするユーザ個人の電子証明書 (クライアント証明書)とその秘密鍵。 サーバ側: サーバ管理者が信頼する認証局の証明書(複数)。サーバはそれらの 認証局が発行したクライアント証明書だけを有効なものと判断します。 (技術的にはあまり正確な記述ではありませんが) 入手方法 クライアント証明書+秘密鍵 : サーバが信頼する認証局からこれらを発行して もらいます。あなたがサーバ管理者なので、自分が作成したプライベート認証局で 発行して各ユーザに配布することもできます。 Orenosp付属のgencertプログラムはサーバ証明書だけでなくクライアント証明書 も生成できます。またEasyCertやOpensslといったツールをつかうことも可能です。 サーバ管理者が信頼する認証局の証明書 : a) プライベート認証局が発行したクライアント証明書だけを認める場合は、 プライベート認証局の証明書。 他の商業認証局からの証明書を認める場合 b) OS(Windows)に信頼する認証局としてプリインストールされている 認証局の証明書を使用する。(Windows Certificate Store) 注意: WinXPのデフォルトではOS内に格納されている信頼する認証局のリストは Mirosoft社により動的に更新されます。留意事項のセクションを参照。 c) Apacheのmodssl向けのものを流用する。 http://www.modssl.org/からmodsslをダウンロードしてきます。 設定方法 1) SSLクライアント認証をrequireに設定する # enable SSL client authentication _ssl_clauth = require 2) SSLクライアント認証においてサーバが信頼する認証局の証明書ストアを指定する -- 自分のプライベート認証局だけを信頼する場合 (a) -- _ssl_cacertstore = file ssl.crt/ca.crt と設定し、自分のCA証明書をssl.crt/ca.crtとして配置します。 なおこの証明書はPEM形式でなけれなりません。 gencertを使っている場合は以下のコマンドを実行します: > cd or > copy myca\cacert.pem ssl.crt\ca.crt -- OSにプリインストールされている認証局のリストを指定する場合 (b) -- _ssl_cacertstore = os と指定しています。SSLクライアント認証を有効にした場合これがデフォルトに なります。 -- Apacheのmodssl向けのものを流用する場合 (c) -- AapacheでSSLCACertificateFileを指定している場合は単一のPEMファイルを指定 します: _ssl_cacertstore = file ssl.crt/ca-bundle.crt ApacheでSSLCACertificatePathでディレクトリを指定している場合は、PEM形式の CA証明書が格納されているディレクトリを指定します: _ssl_cacertstore = dir ssl_ca.crt サーバはこれらの証明書をオン・デマンドで動的にロードします。そのために これらの証明書はsubject nameのhashでインデックスされていなければなりません。 hashはサーバを起動する前に作成しておきます。 (もしくは)/ssl_ca.crtに、バッチプログラム certhash.batとそのヘルパーバッチプログラムnamehash.batがあります。 このディレクトリにCA証明書ファイルをいれて、certhash.batを実行して 必要なhashを作成します。 - certhash.batが動作するにはCA証明書ファイルは"XXXX.crt"と名づけられて いる必要があります。 - namehash.bat内でopenssl.exeのパスを指定してください。 テスト クライアント認証はSSL接続のハンドシェイク時に行われます。 プログラムのよっては非常に分かりにくいエラーで終わるものが多々あります。 パケットトレースで問題を突き止めることができます。 a) openssl.exeのs_clientコマンドを使ってSSLネゴシエーションの中を 検査する。 >openssl s_client -connect localhost:443 b) SSL対応のネットワークスニファーでパケットトレースを採取 recommended ssldump by Eric Rescorla Homepage http://www.rtfm.com/ssldump/ Windows binary http://home.comcast.net/~makataoka/misc/ c) サーバ側でトレースを採取 _trace_level = 1 を設定するとevent.logにSSLハンドシェイク時のトレースが出力されます 留意事項 - 方法b) OS(Windows)に信頼する認証局としてプリインストールされている 認証局の証明書を使用する場合の注意事項 Windows XPではデフォルトで「ルート証明書の更新」というコンポーネントが 有効になっています。IEと連動して、信頼するルートCAのリストが変更されます。 ただしOrenospは起動時にこのルートCAのリストを自メモリに読み込んでしまう ので、Orenosp起動後にこのリストが変更されてもOrenospを再起動しない限り 有効になりません。 また、信頼するルートCAのリストというSSLクライアント証明の根本となる 情報が他社により動的に更新されるのはサイトのセキュリティポリシーに 適合しない場合があります。 これを無効にしたい場合は以下の手順に従ってください。 コントロールパネルの[Windows コンポーネントの追加と削除] から、 [ルート証明書の更新] を削除します。(JP283717参照) - 方法b) で信頼する認証局のリストに自分のプライベートCAも追加したい場合は 以下の手順で行います。 _ssl_cacertstore = os を設定する。 次にcertmemo_jp.txtの「Windows Certificate Store for Service Programs」 セクションに従い、プライベートCAの証明書をOrenosv/Orenospサービスが 信頼する認証局のリストに追加します。 SSL Profiles ============ 複数のSSL設定 Orenosp 0.4.0 / Orenosv 0.6.0から、複数のSSL設定を持つことが可能に なりました。例えば2つのリスンポート(IPアドレス+TCPポート)それぞれに 違ったサーバ証明書などを設定でき、一方のリスンポートだけクライアント認証 を行うといったことが可能になります。 またOrenospではHTTPSバックエンドサーバに接続する際に使用するSSL設定も 複数用意できます。HTTPSバックエンドサーバがクライアント認証を要求する場合 などで必須の機能となります。 SSL Profileの設定 まず定義するSSLプロファイルの名前を決め設定します。 _sslprof_define = spex1 次にそのSSLプロファイルのpeerタイプを定義します。上で定義したSSLプロファイル の名前がパラメータ名の一部になっていることに注意してください。 ptypeは server から client のいずれかです。クライアントからのSSL接続を 受け付ける文脈で使用するのが server です。バックエンドサーバへのSSL接続を 張る文脈で使うのが client です。 _sslprof_spex1_ptype = server あとは既存のSSLパラメータを、SSLプロファイル用パラメータを使って 書いていきます。 _ssl_keypass -> _sslprof_spex1_keypass _ssl_mycertstore -> _sslprof_spex1_mycertstore _ssl_clauth -> _sslprof_spex1_clauth _ssl_cacertstore -> _sslprof_spex1_cacertstore _ssl_ciphers -> _sslprof_spex1_ciphers svauthはptypeがclientのSSLプロファイルで使用します。SSLサーバに接続する 際に、サーバ証明書の有効性やホスト名の一致を確認しサーバを認証します。 _sslprof_spex1_svauth = {none|option|require} ビルトインSSLプロファイル 定義済みSSLプロファイルが2つ存在します。 "svdflt" : サーバサイドSSLプロファイル (ptype=server) _sslprof_define = svdflt _sslprof_svdflt_ptype = server _sslprof_svdflt_mycertstore = file ssl.crt/server.crt ssl.key/server.key _sslprof_svdflt_keypass = orenosp _sslprof_svdflt_clauth = none _sslprof_svdflt_cacertstore = file ssl.key/root.pem "cldflt" : クライアントサイドSSLプロファイル (ptype=client) _sslprof_define = cldflt _sslprof_cldflt_ptype = client _sslprof_cldflt_svauth = none _sslprof_cldflt_cacertstore = os サーバSSLプロファイルが要求される文脈では"svdflt"がデフォルトで使用されます。 クライアントSSLプロファイルが要求される文脈では"cldflt"がデフォルトで使用 されます。 また旧バージョンとの互換性のために、 proxy_ssl_xxx (Orenosp) ftp_ssl_xxx (Orenosv) というパラメータ定義は、svdflt SSLプロファイルにマッピングするように _ssl_xxxを_sslprof_svdflt_xxxに変換しています。 さらにこれらビルトインSSLプロファイルを設定ファイル内で再定義することも できます。まず _sslprof_define = svdflt から始めて、必要な全てのパラメータを_sslprof_svdflt_xxxで設定 してください。ptypeパラメータも設定する必要がありますが、値は変更しては いけません。svdfltのptypeは"server"、cldfltは"client"にしてください。 SSLプロファイルのダンプ "proxy_sslprof_printinfo = 1"を設定すると、event.logに有効なSSLパラメータが すべてダンプされます。 --- example for using three different SSL profiles to use three SSL certificate --- # 1st listen port uses default SSL profile proxy_listen_name = lis-ssl 0.0.0.0@443 https # 2nd listen port uses SSL profile "site2" proxy_listen_name = lis-ssl2 0.0.0.0@4443 https -ssl_cli=site2 # 3rd listen port uses SSL profile "site3" proxy_listen_name = lis-ssl3 0.0.0.0@4444 https -ssl_cli=site3 # # settings for default server SSL profile # # use proxy_ssl_xxx to set required attributes # # define SSL profile "site2" # proxy_sslprof_define = site2 proxy_sslprof_site2_ptype = server proxy_sslprof_site2_mycertstore = file ssl.crt/server-site2.crt \ ssl.key/server-site2.key # # define SSL profile "site3" # proxy_sslprof_define = site3 proxy_sslprof_site3_ptype = server proxy_sslprof_site3_mycertstore = file ssl.crt/server-site3.crt \ ssl.key/server-site3.key --- EOF