Posts in category http

在 Basic 认证下多个 Trac 服务器之间的单点登陆

由于 Trac 目前只能支持单个项目,所以,很多时候需要在多个 Trac 服务器间进行链接等的互相关联,Trac 对这种需求的回答是 InterTrac(中文) ,不过 InterTrac 并不处理多个 Trac 服务器之间的统一登陆问题;

原理

在使用 Apache httpd 的Basic 认证模式下,如果多个 Trac 服务器使用相同的认证来源(比如使用相同的LDAP服务器,或者相同的passwd文件),那么就可以比较方便的实现多个 Trac 服务器间的单点登陆,要点包括:

  1. 一般情况下与 Trac 服务器集成的 httpd 会设置对 .../login 地址的用户认证,如果在当前服务器中设置一个指向其他服务器的反向代理,并且对反向代理后的 url 设置一个当前服务器的 LocationMatch 认证控制,那么:
    1. 如果用户已经登陆当前 Trac,那么访问反向代理后的 url 就可以自动获得已有的 Basic 认证信息(因为二者是一个服务器地址);
    2. 在已经具有 Basic 认证信息的情况下,通过反向代理访问到真正的服务器时,Basic 认证信息同样可以传递,从而可以直接登陆到外部服务器,不需要用户再次输入用户名/密码;
  2. 借用 Trac 处理 .../login 时对 referer HTTP 参数的 redirect_back 特性,如果在访问 .../login 时使用参数 ?referer=....,那么完成 Basic 认证后,可以重定向到需要显示的页面;
  3. 通过在 trac.ini 中设置类似 prj1.url = /trac/prj1/login?referer=/trac/prj1InterTrac URL,可以保证使用 InterTrac 语法编写的 TracLinks 通过 .../login URL 实现自动登陆然后跳转到具体页面,从而完成单点登录;

具体实现举例

  • httpd.conf
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    ProxyRequests Off
    # ================================================= 
    # Proxy to http://another-server/trac/prj1
    # =================================================
    <proxy http://another-server/trac/prj1>
        AllowOverride None
        Order Deny,Allow
        Allow from all
    </proxy>
    ProxyPass /trac/prj1 http://another-server/trac/prj1
    ProxyPassReverse /trac/prj1 http://another-server/trac/prj1
    # ================================================= 
    # Proxy to http://another-server2/trac/prj2
    # =================================================
    <proxy http://another-server2/trac/prj2>
        AllowOverride None
        Order Deny,Allow
        Allow from all
    </proxy>
    ProxyPass /trac/prj2 http://another-server2/trac/prj2
    ProxyPassReverse /trac/prj2 http://another-server2/trac/prj2
    
    # 这里定义的 AuthType 必需是 Basic, 其他的配置项与当前 Trac 要保持一致,即这几个 Trac 需要使用同一个用户认证机制和认证来源
    # 具体需要几个 LocationMatch,取决于反向代理配置是的 URL 设置情况,这里因为反向代理的两台服务器都被定义在 /trac 下,所以可以使用一个 LocationMatch 来进行用户认证
    <LocationMatch "/trac/[^/]+/login">
        AuthType Basic
        AuthBasicProvider "ldap"
        AuthLDAPUrl "ldap://domain-server/DC=thinkbase,DC=net?sAMAccountName?sub?(objectClass=*)"
        AuthLDAPBindDN "CN=trac-ldap-user,OU=ServerAccountsGroup,DC=thinkbase,DC=net"
        AuthLDAPBindPassword "**********"
    
        AuthName "Trac 1.0.1"
    
        Require valid-user
    </LocationMatch>
    
  • trac.ini
    [intertrac]
    P1 = prj1
    prj1.title = Project 1 Trac
    prj1.url = /trac/prj1/login?referer=/trac/prj1
    P2 = prj2
    prj2.title = Project 2 Trac
    prj2.url = /trac/prj2/login?referer=/trac/prj2
    

另外一种方式

如果两个 Trac 服务器的认证来源不一致(比如一个使用 LDAP 认证,一个使用 passwd 文件认证,用户名和密码都不相同),是否可以实现类似的效果呢?

答案是可以的,不过需要有一个前提,就是使用固定的用户/密码访问另外那个 Trac 服务器,具体来说,在 httpd.conf 中可以省去 <LocationMatch 定义认证方式的部分,而是在 <proxy 中通过 HTTP Header Authorization 写死 Basic 认证的用户名和密码:

  • httpd.conf
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule headers_module modules/mod_headers.so
    ProxyRequests Off
    # ================================================= 
    # Proxy to http://another-server/trac/prj1
    # =================================================
    <proxy http://another-server/trac/prj1>
        AllowOverride None
        Order Deny,Allow
        Allow from all
        # 这里固定设置反向代理转发时的 Basic 认证用户名和密码, dXNlcjE6cGFzc3dkMQ= 是命令行 'echo -n user1:passwd1 | base64' 的运行结果
        RequestHeader set Authorization "Basic dXNlcjE6cGFzc3dkMQ="
    </proxy>
    ProxyPass /trac/prj1 http://another-server/trac/prj1
    ProxyPassReverse /trac/prj1 http://another-server/trac/prj1
    

演示

就 thinkbase.net 站点的两个 trac 环境作了一个示例。当然,因为这两个 trac 环境是部署在同一个 apache httpd 上的,所以不需要在 httpd.conf 中增加配置。

参考

END

nginx 反向代理功能介绍及在Windows下使用的Portable版本

想做一个公网访问内网的反向代理,但是在公网机器上的 Apache 怎么也安装不上(那个机器已经安装了两个 Apache,不知道是不是这方面的原因),于是就研究了一下如何使用 nginx 来实现反向代理。

搜索了一下资料,发现 nginx 似乎比 Apache 更好用,包括:

  • 配置的方式类似 json,比较容易阅读;
  • 运行简单,Windows 平台上的二进制文件本身就是解压即可运行,够 “Portable”;
  • 在网上找到了使用 Windows Service Wrapper 将 nginx 转为一个 Windows 服务的方法,经试验简单有效,见 Nginx Windows Service

nginx 自然在其 官网下载,本文使用的是 Stable version, nginx/Windows-1.2.7;

winsw(Windows Service Wrapper)原来 host 在 https://kenai.com/,不过Oracle 收购 Sun 之后这个网站似乎受到一些影响,目前已经转到了 github 上: https://github.com/kohsuke/winsw/ (是用 C# 编写的,呵呵), 其二进制文件可以在 Nginx Windows Service 文中提到的地点 http://download.java.net/maven/2/com/sun/winsw/winsw/ 下载(似乎是一个 maven 的仓库?);

本文附件中的 “PortableNgnix” 只是简单的将解压后的 nginx Windows 程序和 winsw 合并在一起而已,其中包含一个简单的 proxy 写法示例(将 http://localhost/main/browser/AdminShells/ 反向代理连接到 http://thinkbase.net/main/browser/AdminShells/ ):

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location /main/browser/AdminShells/ {
                proxy_pass              http://thinkbase.net/main/browser/AdminShells/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

其实很多时候还有更简单的写法,比如下面这个反向代理 svn 服务器的例子:

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       81;
        server_name  localhost;

        location / {
                proxy_pass              http://192.168.0.77:8080/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

使用 winsw 创建 Windows Service 的过程也很简单,附件 PortableNginx.7z 中的例子是假设 nginx 解压后在 D:\PortableNginx 目录下的情况:

<service>
    <id>nginx-reverse-proxy</id>
    <name>nginx reverse proxy</name>
    <description>nginx reverse proxy</description>
    <executable>D:\PortableNginx\nginx\nginx.exe</executable>
    <logpath>D:\PortableNginx\nginx\logs</logpath>
    <logmode>roll</logmode>
    <depend></depend>
    <startargument>-p D:\PortableNginx\nginx -c D:\PortableNginx\nginx\proxy.conf</startargument>
    <stopargument>-p D:\PortableNginx\nginx -s stop</stopargument>
</service>

更多细节可以继续研究附件(参见其中的 readme.txt),或者把附件解压后自己体验,下面是 winsw 产生的 Windows Servicce 以及 Service 运行时产生的相关文件截图,供参考: .