顯示具有 auth 標籤的文章。 顯示所有文章
顯示具有 auth 標籤的文章。 顯示所有文章

2017年2月24日 星期五

Captive portal 研究心得,以 iptables 實作

之前略知使用 Taipei Free 或 CHT Wi-Fi時,會彈跳出認證(登入)的網頁,但卻不知其所以然,直到最近研究了 Captive portal 的東西。一開始用 Captive portal 關鍵字找了一些 RFC 文件,殊不知那些都是煙霧彈 XD 如:
經過了一陣抓封包後,簡言之,透過網路管控,當符合以下情境時,各個 OS 內的網路偵測小程式,就會彈跳視窗:
  1. 用戶連上 router 時,可以進行 DNS lookup
  2. 未通過認證的用戶,無法透過 router 進行網路連線請求,如連上 facebook.com
  3. 通過認證的用戶,透過 router 可以正常使用網路
在各個 OS 內,都有一隻小程式時時關注著網路變化,當網路狀態改變且尚未有連外環境,這時程式會自動進行網路連線偵測,概念上就是去連各個 OS 自訂的一個網頁位置,看看能不能抓到東西,且東西是否正常。若不正常時,就會判斷網路是要認證的,接著就會彈跳出認證視窗。



至於 router 上的實作,簡單的說,就是透過防火牆機制:
  1. 防火牆設計各種狀態,例如未認證,已認證的 flag (mark)
  2. 當用戶完成認證時,透過 CGI 執行防火牆指令,給予標記 (mark)
  3. 允許已標記的 client 封包通行
至於完整的實作,可以參考:
以下是同事分別安裝 wifidog 跟 NoCatSplash 取出的防火牆規則,以 wifidog 產出的:

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N WD_wlan0_AuthServs
-N WD_wlan0_Global
-N WD_wlan0_Internet
-N WD_wlan0_Known
-N WD_wlan0_Locked
-N WD_wlan0_Unknown
-N WD_wlan0_Validate
-A FORWARD -i wlan0 -j WD_wlan0_Internet
-A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wlan0 -o eth0 -j ACCEPT
-A WD_wlan0_AuthServs -d SERVER_IP/32 -j ACCEPT
-A WD_wlan0_Internet -m state --state INVALID -j DROP
-A WD_wlan0_Internet -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-A WD_wlan0_Internet -j WD_wlan0_AuthServs
-A WD_wlan0_Internet -m mark --mark 0x254 -j WD_wlan0_Locked
-A WD_wlan0_Internet -j WD_wlan0_Global
-A WD_wlan0_Internet -m mark --mark 0x1 -j WD_wlan0_Validate
-A WD_wlan0_Internet -m mark --mark 0x2 -j WD_wlan0_Known
-A WD_wlan0_Internet -j WD_wlan0_Unknown
-A WD_wlan0_Known -j ACCEPT
-A WD_wlan0_Locked -j REJECT --reject-with icmp-port-unreachable
-A WD_wlan0_Unknown -p udp -m udp --dport 53 -j ACCEPT
-A WD_wlan0_Unknown -p tcp -m tcp --dport 53 -j ACCEPT
-A WD_wlan0_Unknown -p udp -m udp --dport 67 -j ACCEPT
-A WD_wlan0_Unknown -p tcp -m tcp --dport 67 -j ACCEPT
-A WD_wlan0_Unknown -j REJECT --reject-with icmp-port-unreachable
-A WD_wlan0_Validate -j ACCEPT


以 NoCatSplash 產出的 iptables 為筆記:

$ iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N NoCat
-N NoCat_Inbound
-N NoCat_Ports
-A FORWARD -j NoCat
-A NoCat -j NoCat_Ports
-A NoCat -j NoCat_Inbound
-A NoCat -s SERVER_IP/24 -i wlan0 -m mark --mark 0x1 -j ACCEPT
-A NoCat -s SERVER_IP/24 -i wlan0 -m mark --mark 0x2 -j ACCEPT
-A NoCat -s SERVER_IP/24 -i wlan0 -m mark --mark 0x3 -j ACCEPT
-A NoCat -j DROP
-A NoCat_Ports -i wlan0 -p tcp -m tcp --dport 25 -m mark --mark 0x3 -j DROP
-A NoCat_Ports -i wlan0 -p udp -m udp --dport 25 -m mark --mark 0x3 -j DROP
$ iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N NoCat_Capture
-N NoCat_NAT
-A PREROUTING -j NoCat_Capture
-A POSTROUTING -j NoCat_NAT
-A NoCat_Capture -p tcp -m mark --mark 0x4 -m tcp --dport 80 -j REDIRECT --to-ports 5280
-A NoCat_Capture -p tcp -m mark --mark 0x4 -m tcp --dport 443 -j REDIRECT --to-ports 5280
-A NoCat_NAT -s SERVER_IP/24 -o eth0 -m mark --mark 0x1 -j MASQUERADE
-A NoCat_NAT -s SERVER_IP/24 -o eth0 -m mark --mark 0x2 -j MASQUERADE
-A NoCat_NAT -s SERVER_IP/24 -o eth0 -m mark --mark 0x3 -j MASQUERADE


其他 iptabes 簡介:

2016年1月22日 星期五

DevOps 筆記 - Jenkins 處理 Git Submodule Authentication/Credential 問題

已經很習慣用 Bitbucket 做 git service,然後有個 project 裡有個 sub-project 一樣有存取控管,而 Jenkins 預設只有第一層存取時,可以正確透過 Credentials 來解決,但是 submodule 就會失敗。

依照原理解法有兩招:

  1. 直接在 Jenkins 執行者的 $HOME/.ssh/ 去撰寫底層 ssh 連線認證方式
  2. 使用 Jenkins plugin - SSH Agent Plugin

為了管理維護方便,當然就用 SSH Agent Plugin 啦,安裝完後,每一個 Project 就會多一個 SSH Agent 的設定選項,只需設定好即可。

另外,有一派會建議把原先 Jenkins Project 裡的 Git Credentials 去掉,一律都用 SSH Agent Plugin 的設定,但這招會導致後續要做 Git Publisher 要做 git tag 時產生問題。

2016年1月14日 星期四

[Perl] 測試及修正 Perl 5.10.0 的 Email:Send 支援 SMTP + TLS + AUTH 寄信方式 @ perlbrew 5.10.0 / Ubuntu 14.04

上次一摸 Perl 有點久了 Orz 這個問題主要是發生在舊版 Bugzilla 3.0.5 on Perl 5.10.0 環境上,想要走 SMTP + TLS + AUTH 的寄信方式,只是核心部分抽出來驗證後,只須如此就能打造測試環境了:

$ sudo apt-get install perlbrew libssl-dev
$ perlbrew init
$ perlbrew --notest install 5.10.0
$ perlbrew user 5.10.0
bash-4.3$ perl -v

This is perl, v5.10.0 built for x86_64-linux

Copyright 1987-2007, Larry Wall

bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'TimeDate')"
bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'Date::Format')"
bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'Email::Address')"
bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'Email::MIME')"
bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'Email::Send')"
bash-4.3$ perl -MCPAN -e "CPAN::Shell->notest('install', 'Net::SMTP::TLS')"


如此一來,就可以寫簡單的 Perl 程式測試寄信,此例是處理騰訊企業郵箱的寄信方式:

bash-4.3$ vim send.pl
#!/usr/bin/perl

# http://search.cpan.org/dist/Email-Send/lib/Email/Send.pm
use Date::Format qw(time2str);
use Encode::MIME::Header;
use Email::Address;
use Email::MIME;
use Email::MIME::Modifier;
use Email::Send;
use MIME::Base64;

push @args,
        #Host  => 'hwsmtp.exmail.qq.com:465',
        #Host  => 'smtp.exmail.qq.com:465',
        #Host  => 'smtp.exmail.qq.com:587',
        #Host  => 'smtp.exmail.qq.com',
        Host  => 'hwsmtp.exmail.qq.com',
        username => 'account@my.domainname',
        password => 'password_for_account',
        Hello => 'localhost',
        #ssl => 1,
        tls => 1,
        Debug => 1;

$body = "Hello World";
$method = 'SMTP';
$from = 'account@my.domainname';
$to = 'account@my.domainname';
$subject = "Test Mail";

my $email = ref($msg) ? $msg : Email::MIME->new($body);
$email->header_set('MIME-Version', '1.0') if !$email->header('MIME-Version');
$email->header_set('From', $from);
$email->header_set('To', $to);
$email->header_set('Date', time2str("%a, %e %b %Y %T %z", time()));
$email->header_set('Subject', $subject);
foreach my $part ($email->parts) {
        $part->charset_set('UTF-8');
        #$part->encoding_set('quoted-printable') if !is_7bit_clean($part->body);
}

my $mailer = Email::Send->new({ mailer => $method, mailer_args => \@args });
my $retval = $mailer->send($email);

print $retval;


執行看看:

bash-4.3$ perl send.pl
invalid SSL_version specified at /home/ubuntu/perl5/perlbrew/perls/perl-5.10.0/lib/site_perl/5.10.0/IO/Socket/SSL.pm line 568


人工修正:

bash-4.3$ vim /home/ubuntu/perl5/perlbrew/perls/perl-5.10.0/lib/site_perl/5.10.0/IO/Socket/SSL.pm
將 2210行註解舊的,並更新成新的 Regular Expressiong
#m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1(?:_?[12])?))$}i
m{^(!?)(?:(SSL(?:v2|v3|v23|v2/3))|(TLSv1[12]?))}i


再次執行:

bash-4.3$ perl test/send.pl
Message sent


因此,這只是單純 Perl 5.10.0 的 SSL.pm 的 TLS 規則影響,造成使用騰訊企業郵箱時,透過 SMTP + TLS + AUTH 寄信時無法成功。而這篇的目的只是記錄透過 Perl Email::Send 寄信走認證的筆記 XD 另外, Email::Send 走 SSL + AUTH 一直沒成功過 Orz

2014年2月26日 星期三

[Linux] 使用 Node.js 與 MongoDB 溝通與帳號認證 @ Ubuntu 12.04

透過 apt-get 安裝 node.js:

$ sudo apt-get install python-software-properties
$ sudo add-apt-repository ppa:chris-lea/node.js
$ sudo apt-get update
$ sudo apt-get install nodejs


建立 project:

$ cd project
$ npm install mongodb
$ vim test.js
var Db = require('mongodb').Db,
        MongoClient = require('mongodb').MongoClient;

var db_host = 'localhost';
var db_port = 27017;
var auth_db = 'admin';
var auth_name = 'account';
var auth_pass = 'password';

MongoClient.connect("mongodb://"+auth_name+":"+auth_pass+"@"+db_host+":"+db_port, function(err, db) {
        console.log(err);
        console.log(db.databaseName);
        db.close();
});

MongoClient.connect("mongodb://"+db_host+":"+db_port, function(err, db) {
        db.authenticate(auth_name, auth_pass, function(err, ret) {
                console.log(err);
       console.log(db.databaseName);
                console.log(ret);
       db.close();
        });
});
$ node test.js
Failed to load c++ bson extension, using pure JS version
null
admin
null
admin
true


以上為兩種跟 mongodb 進行認證的方式,一種是寫在 URI 中,另一種則是透過 db.authenticate 方式,至於這份程式的輸出不見得 "true" 是在最後一列,也有可能在第三列,這是因為 node.js async 架構關係,在這份 code 中不保證哪個 function 先跑。

如果 mongodb 本身要求認證,而未認證則會有錯誤訊息:

{ [MongoError: unauthorized] name: 'MongoError', ok: 0, errmsg: 'unauthorized' }

比較疑惑的地方是對於 auth_db 的部分,之前在用 pymongo 時,或是直接用 mongo 指令時,必須透過指定 authenticationDatabase 才能通過認證,但在 node.js 中,似乎沒有問題?再來摸看看好了。

2014年2月18日 星期二

[Linux] MongoDB Replica Set with Auth & KeyFile @ Ubuntu 12.04

mongod shutdown error

建 cluster 不見得需要帳號管控,因為多數處在保護的網路環境,而 MongoDB 預設沒有帳密管控且帳密管控做的很簡單,分成 read-only 跟 read-write 模式。而使用認證的主因是為了遠端關掉機器,沒有認證機制的服務僅能透過 localhost 關掉服務,有一派說是透過 service mongodb stop 指令,又有一派說直接 kill process 即可,但有文章說如此容易造成問題?還是要用正式的關機流程比較妥( mongo> db.shutdownServer() )。

參考文件:
架設 Replica Set 的流程:
  1. 啟動多台 mongod --replSet set_name
  2. 挑選一台 mongod 登入
  3. 使用 rs.init() 初始化後,再用 rs.add() 加入其他 mongod 或是使用 db.runCommand({'replSetInitiate':{'members':[]}}) 一次新增
架設需要認證的 Replica Set 的流程:
  1. 用 default 模式啟動一台 mongod
  2. 建立帳號
  3. 建立 keyFile (檔案內容隨意,但需要多過6個字元)
  4. 關掉後以 --replSet set_name 與 --keyFile key_file_path 模式啟動多支 mongod
  5. 登入一台 mongod 以及完成帳號認證
  6. 使用 rs.init() 初始化後,再用 rs.add() 加入其他 mongod 或是使用 db.runCommand({'replSetInitiate':{'members':[]}}) 一次新增
上述兩者流程的差別在於後者要先建帳號後,再用 --replSet 跟 --keyFile 模式啟動。而後,為了測試就寫了隻 script 筆記一下:

未使用認證模式:

$ python replset_init.py --reset

Init DB(0), Port: 30000, Path: /home/id/data/mongodb-study/cluster/db/db-0
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-0 --port 30000 --oplogSize 700 --logpath /home/id/data/mongodb-study/cluster/log/db-0.log --rest --replSet firstset

Init DB(1), Port: 30001, Path: /home/id/data/mongodb-study/cluster/db/db-1
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-1 --port 30001 --oplogSize 700 --logpath /home/id/data/mongodb-study/cluster/log/db-1.log --rest --replSet firstset

Init DB(2), Port: 30002, Path: /home/id/data/mongodb-study/cluster/db/db-2
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-2 --port 30002 --oplogSize 700 --logpath /home/id/data/mongodb-study/cluster/log/db-2.log --rest --replSet firstset

nohup: ignoring input and appending output to `nohup.out'
nohup: ignoring input and appending output to `nohup.out'
nohup: ignoring input and appending output to `nohup.out'

Waiting...
        localhost:30000: .....OK
        localhost:30001: OK
        localhost:30002: OK

Connect to localhost:30000

Initialize the First Replica Set:

$ monogo localhost:30000/admin
mongo> db.runCommand( {'replSetInitiate': {'_id': 'firstset', 'members': [{'host': 'localhost:30000', '_id': 1}, {'host': 'localhost:30001', '_id': 2}, {'host': 'localhost:30002', '_id': 3}]}} )

Result:
{u'info': u'Config now saved locally.  Should come online in about a minute.', u'ok': 1.0}

All is done.

server info:
 $ mongo localhost:30000/admin --eval 'printjson(rs.status())'

shutdown servers:
 $ mongo localhost:30000/admin --eval 'db.shutdownServer()'
 $ mongo localhost:30001/admin --eval 'db.shutdownServer()'
 $ mongo localhost:30002/admin --eval 'db.shutdownServer()'


使用認證模式:

$ python replset_init.py --reset --auth-key-file keyfile --auth-user account --auth-pass password

Init DB(0), Port: 30000, Path: /home/id/data/mongodb-study/cluster/db/db-0
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-0 --port 30000 --oplogSize 700 --logpath /home/id/data/mongodb-study/cluster/log/db-0.log --rest
nohup: ignoring input and appending output to `nohup.out'

Waiting...
        localhost:30000: ..OK

Connect to localhost:30000

Initialize the First Replica Set:

$ monogo localhost:30000/admin
mongo> db.addUser( {user: "account", pwd:"password", roles:["userAdminAnyDatabase"] })

Add account done.

Restart the mongod:

Init DB(0), Port: 30000, Path: /home/id/data/mongodb-study/cluster/db/db-0
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-0 --port 30000 --oplogSize 700 --logpath /home/id/data/mongodb-study/cluster/log/db-0.log --rest --replSet firstset --keyFile keyfile

Init DB(1), Port: 30001, Path: /home/id/data/mongodb-study/cluster/db/db-1
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-1 --port 30001 --oplogSize 700 --logpath /home/id/data/mongodb-
study/cluster/log/db-1.log --rest --replSet firstset --keyFile keyfile

nohup: ignoring input and appending output to `nohup.out'
Init DB(2), Port: 30002, Path: /home/id/data/mongodb-study/cluster/db/db-2
 $ mongod --dbpath /home/id/data/mongodb-study/cluster/db/db-2 --port 30002 --oplogSize 700 --logpath /home/id/data/mongodb-
study/cluster/log/db-2.log --rest --replSet firstset --keyFile keyfile

nohup: ignoring input and appending output to `nohup.out'
nohup: ignoring input and appending output to `nohup.out'
nohup: ignoring input and appending output to `nohup.out'

Waiting...
        localhost:30000: .......OK
        localhost:30001: ...................................OK
        localhost:30002: .OK

Connect to localhost:30000

Initialize the First Replica Set:

$ monogo localhost:30000/admin
mongo> db.runCommand( {'replSetInitiate': {'_id': 'firstset', 'members': [{'host': 'localhost:30000', '_id': 1}, {'host': 'localhost:30001', '_id': 2}, {'host': 'localhost:30002', '_id': 3}]}} )

Result:
{u'info': u'Config now saved locally.  Should come online in about a minute.', u'ok': 1.0}

All is done.

server info:
 $ mongo localhost:30000/admin -u account -p password --eval 'printjson(rs.status())'

shutdown servers:
 $ mongo localhost:30000/admin -u account -p password --eval 'db.shutdownServer()'
 $ mongo localhost:30001/admin -u account -p password --eval 'db.shutdownServer()'
 $ mongo localhost:30002/admin -u account -p password --eval 'db.shutdownServer()'

2014年1月12日 星期日

[Linux] Nginx + Auth + PHP + CodeIgniter @ Ubuntu 12.04

Nginx Authentication 可以參考官網 HttpAuthBasicModule / ngx_http_auth_basic_module 設定:

location ~^ /ci/  {
  auth_basic            "Restricted";
  auth_basic_user_file  htpasswd;
}


由於 nginx 用 apt-get 安裝,此例 htpasswd 則是位於 /etc/nginx/htpasswd ,若不確定的話,翻一下 nginx access/error logs 來看。

比較特別,如果保護的是一個 location 包含要運行 PHP 程式的話,裡頭需要把完整的 PHP 處理也定義好,據說是因為 nginx auth_basic module 不會繼續往下讀起 nginx.conf。

解法:

location ~^ /ci/  {
  auth_basic            "Restricted";
  auth_basic_user_file  htpasswd;

  # for codeigniter
  index  index.html index.htm index.php;
  try_files $uri $uri/ /ci/index.php;

  # for php
  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

    # With php5-cgi alone:
    fastcgi_pass 127.0.0.1:9000;

    # With php5-fpm:
    #fastcgi_pass unix:/var/run/php5-fpm.sock;

    fastcgi_index index.php;
    include fastcgi_params;
}