ApacheでのBasic認証とIPアドレスによるアクセス制限

Apacheで、以下の条件のいずれかを満たす場合にのみコンテンツが閲覧できるようにした。

  • 基本は、Basic認証でユーザ名とパスワードを要求したい。
  • 指定したネットワークセグメント(192.168.100.0/24)に属するIPアドレスからアクセスはBasic認証なしにしたい。

実際の設定は以下のような感じ。

AuthUserFile  /etc/httpd/conf.d/my-site-htpasswd
AuthGroupFile /dev/null
AuthName      "Please Enter Your Password"
AuthType      Basic
Require valid-user

Satisfy Any

Order allow,deny
Allow from 192.168.100.0/24

Satisfy ディレクティブが肝で、AllとAnyでは以下の違いがあります。(デフォルトは、Allになります)

  • Satisfy All: アドレスによる アクセス制限を満たし、かつ正しいユーザ名とパスワードを入力すること
  • Satisfy Any: アドレスによる アクセス制限を満たすか、 または正しいユーザ名とパスワードの入力をすること

Twtter Streaming API(filter)を使ったサンプルプログラム

TwitterのStreaming APIの1つのfilterを試しに作ってみた。サンプルは、「iPad」という単語を含むつぶやきを垂れ流し続けます。

$ cat stream_filter.php
<?php

define('ID', '自分のTwitterアカウントのscreen_nameに置き換えて下さい');
define('PW', '自分のTwitterアカウントのpasswordに置き換えて下さい');
define('BASIC_AUTH', base64_encode(ID.':'.PW));
define('STREAM_FILTER', 'http://stream.twitter.com/1/statuses/filter.json');

$ctx = stream_context_create(
	array(
		'http' => array(
			'method' => 'POST',
			'header' => "Authorization: Basic " . BASIC_AUTH . "\r\n" .
			            "Content-type: application/x-www-form-urlencoded\r\n",	
			'content' => http_build_query(array('track' => 'iPad'))
		)
	)
);
$stream = fopen(STREAM_FILTER, 'r', false, $ctx);
while ($json = fgets($stream)) {
	$tweet = json_decode($json, true);
	if (!array_key_exists('text', $tweet)) continue;
        echo $tweet['user']['screen_name'] . '(' . $tweet['user']['name'] . "):\n";
        echo $tweet['text'] . "\n";
        echo "\ttweeted at " . date('Y/m/d H:i:s', strtotime($tweet['created_at'])) . "\n";
        echo "-------------------------------------------------------------------------\n";
}
fclose($stream);

PHP 5.2.0以降、もしくはPECL Jsonがインストールされてある必要があります。(あとエラー処理はやってないです)

Basic認証用のHTTPリクエストヘッダーの送信方法

プログラム内でBasic認証を行いたい場合、HTTPリクエストヘッダーを送信するだけでよいので、その手順をメモしておきます。

手順はいたって簡単で、「認証用ID:認証用Password」をbase64エンコードした結果の文字列を使うだけです。PHPだと以下のワンライナーで簡単に取得できます。(例は、IDがfoo、Passwordがbarになります)

$ php -r 'echo base64_encode("foo:bar");'
Zm9vOmJhcg==

上記の値を使い、以下の1行をHttpリクエストヘッダーで送信することでBasic認証に成功します。

Authorization: Basic Zm9vOmJhcg==

PHPでTwitterのPublic Timeline上のつぶやき(20件分)を表示する

Objective-C版のオマケでPHP版も書いてみた。

HTTP 拡張モジュールを使っているので、事前にpecl-httpをインストールしておく必要があります。(Dag RPM Reposiotryを有効にしてyumでインストールしています)

$ sudo yum install php-pecl-http

ざっくり書くとこんな感じかな。

<?php
$req = new HttpRequest('http://api.twitter.com/1/statuses/public_timeline.rss', HttpRequest::METH_GET);
try {
        $req->send();
        if ($req->getResponseCode() == 200) {
                $rss = $req->getResponseBody();
                $xml = new SimpleXMLElement($rss);
                $nodes = $xml->xpath('/rss/channel/item/title');
                foreach ($nodes as $node) {
                        echo $node . "\n";
                }
        }
} catch (HttpException $ex) {
        echo "[ERROR]: " . $ex->getMessage() . ' ' . $ex->getFile() . ' line at ' . $ex->getLine() . "\n";
}

Objective-CでTwitterのPublic Timeline上のつぶやき(20件分)を表示する

とりあえず試してみたかっただけなので、エラー処理とか省いてます。

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
	NSURL* url;
	NSXMLDocument* document;
	NSArray* nodes;

	url = [NSURL URLWithString:@"http://twitter.com/statuses/public_timeline.rss"];
	document = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:NULL];
	nodes = [document nodesForXPath:@"/rss/channel/item/title" error:NULL];

	NSXMLNode* node;
	NSEnumerator* enumerator;
	enumerator = [nodes objectEnumerator];
	while (node = [enumerator nextObject]) {
		NSLog(@"%@", [node stringValue]);
	}

	[pool drain];
	return 0;
}

Apache Cassandraをインストールしてみた。

事前準備

Java >= 1.6 である必要があるので、インストールしておく。

$ chmod 755 sudo ./jdk-6u20-linux-i586-rpm.bin 
$ sudo ./jdk-6u20-linux-i586-rpm.bin 
$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Client VM (build 16.3-b01, mixed mode, sharing)

インストール

公式サイトからApache-Cassandraをダウンロードする。(今回選んだのはBinaryの方)

現時点でのバージョンは、0.6.1 なので、以降はそのバージョンで話を進めます。

$ tar zxvf apache-cassandra-0.6.1-bin.tar.gz
$ cd apache-cassandra-0.6.1
$ sudo mkdir -p /var/log/cassandra
$ sudo chown -R `whoami` /var/log/cassandra
$ sudo mkdir -p /var/lib/cassandra
$ sudo chown -R `whoami` /var/lib/cassandra

/usr/local/以下に配置する。

$ sudo mv apache-cassandra-0.6.1 /usr/local/
$ cd /usr/local/
$ sudo ln -s apache-cassandra-0.6.1 cassandra

環境変数をセットする。

CASSANDRA_HOME=/usr/local/cassandra
PATH=$PATH:$CASSANDRA_HOME/bin

ストレージの設定は、$CASSANDRA_HOME/conf/storage-conf.xml になるっぽいので、ざっと目を通す。コメントアウト部分を外すとこんな感じ。

<Storage>
  <!--======================================================================-->
  <!-- Basic Configuration                                                  -->
  <!--======================================================================-->

  <ClusterName>Test Cluster</ClusterName>
  <AutoBootstrap>false</AutoBootstrap>

  <Keyspaces>
    <Keyspace Name="Keyspace1">
      <ColumnFamily Name="Standard1" CompareWith="BytesType"/>
      <ColumnFamily Name="Standard2" 
                    CompareWith="UTF8Type"
                    KeysCached="100%"/>
      <ColumnFamily Name="StandardByUUID1" CompareWith="TimeUUIDType" />
      <ColumnFamily Name="Super1"
                    ColumnType="Super"
                    CompareWith="BytesType"
                    CompareSubcolumnsWith="BytesType" />
      <ColumnFamily Name="Super2"
                    ColumnType="Super"
                    CompareWith="UTF8Type"
                    CompareSubcolumnsWith="UTF8Type"
                    RowsCached="10000"
                    KeysCached="50%"
                    Comment="A column family with supercolumns, whose column and subcolumn names are UTF8 strings"/>
      <ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
      <ReplicationFactor>1</ReplicationFactor>
      <EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
    </Keyspace>
  </Keyspaces>

  <Authenticator>org.apache.cassandra.auth.AllowAllAuthenticator</Authenticator>
  <Partitioner>org.apache.cassandra.dht.RandomPartitioner</Partitioner>
  <InitialToken></InitialToken>
  <CommitLogDirectory>/var/lib/cassandra/commitlog</CommitLogDirectory>
  <DataFileDirectories>
      <DataFileDirectory>/var/lib/cassandra/data</DataFileDirectory>
  </DataFileDirectories>
  <Seeds>
      <Seed>127.0.0.1</Seed>
  </Seeds>
  <RpcTimeoutInMillis>10000</RpcTimeoutInMillis>
  <CommitLogRotationThresholdInMB>128</CommitLogRotationThresholdInMB>
  <ListenAddress>localhost</ListenAddress>
  <StoragePort>7000</StoragePort>
  <ThriftAddress>localhost</ThriftAddress>
  <ThriftPort>9160</ThriftPort>
  <ThriftFramedTransport>false</ThriftFramedTransport>

  <!--======================================================================-->
  <!-- Memory, Disk, and Performance                                        -->
  <!--======================================================================-->

  <DiskAccessMode>auto</DiskAccessMode>
  <RowWarningThresholdInMB>512</RowWarningThresholdInMB>
  <SlicedBufferSizeInKB>64</SlicedBufferSizeInKB>
  <FlushDataBufferSizeInMB>32</FlushDataBufferSizeInMB>
  <FlushIndexBufferSizeInMB>8</FlushIndexBufferSizeInMB>
  <ColumnIndexSizeInKB>64</ColumnIndexSizeInKB>
  <MemtableThroughputInMB>64</MemtableThroughputInMB>
  <BinaryMemtableThroughputInMB>256</BinaryMemtableThroughputInMB>
  <MemtableOperationsInMillions>0.3</MemtableOperationsInMillions>
  <MemtableFlushAfterMinutes>60</MemtableFlushAfterMinutes>
  <ConcurrentReads>8</ConcurrentReads>
  <ConcurrentWrites>32</ConcurrentWrites>
  <CommitLogSync>periodic</CommitLogSync>
  <CommitLogSyncPeriodInMS>10000</CommitLogSyncPeriodInMS>
  <GCGraceSeconds>864000</GCGraceSeconds>

</Storage>

とりあえず起動してみる。

$ cassandra -f
 INFO 16:35:42,332 Auto DiskAccessMode determined to be standard
 INFO 16:35:43,246 Sampling index for /var/lib/cassandra/data/system/LocationInfo-1-Data.db
 INFO 16:35:43,285 Replaying /var/lib/cassandra/commitlog/CommitLog-1274767896157.log
 INFO 16:35:43,290 Log replay complete
 INFO 16:35:43,473 Saved Token found: 159732309793964689006434948302307938157
 INFO 16:35:43,477 Saved ClusterName found: Test Cluster
 INFO 16:35:43,487 Creating new commitlog segment /var/lib/cassandra/commitlog/CommitLog-1274772943487.log
 INFO 16:35:43,536 Starting up server gossip
 INFO 16:35:43,717 Binding thrift service to localhost/127.0.0.1:9160
 INFO 16:35:43,856 Cassandra starting up...

無事に起動したっぽい。ログが /var/log/cassandra/system.log に出力されていることを確認する。

$ cat /var/log/cassandra/system.log 
 INFO [main] 2010-05-25 16:35:42,332 DatabaseDescriptor.java (line 229) Auto DiskAccessMode determined to be standard
 INFO [main] 2010-05-25 16:35:43,246 SSTableReader.java (line 124) Sampling index for /var/lib/cassandra/data/system/LocationInfo-1-Data.db
 INFO [main] 2010-05-25 16:35:43,285 CommitLog.java (line 166) Replaying /var/lib/cassandra/commitlog/CommitLog-1274767896157.log
 INFO [main] 2010-05-25 16:35:43,290 CommitLog.java (line 169) Log replay complete
 INFO [main] 2010-05-25 16:35:43,473 SystemTable.java (line 164) Saved Token found: 159732309793964689006434948302307938157
 INFO [main] 2010-05-25 16:35:43,477 SystemTable.java (line 179) Saved ClusterName found: Test Cluster
 INFO [main] 2010-05-25 16:35:43,487 CommitLogSegment.java (line 50) Creating new commitlog segment /var/lib/cassandra/commitlog/CommitLog-1274772943487.log
 INFO [main] 2010-05-25 16:35:43,536 StorageService.java (line 317) Starting up server gossip
 INFO [main] 2010-05-25 16:35:43,717 CassandraDaemon.java (line 108) Binding thrift service to localhost/127.0.0.1:9160
 INFO [main] 2010-05-25 16:35:43,856 CassandraDaemon.java (line 148) Cassandra starting up...

起動した状態だと、commitlogとdataという2つのディレクトリが作成される。(storage-conf.xml の設定通り)

$ tree /var/lib/cassandra/
/var/lib/cassandra/
|-- commitlog
|   `-- CommitLog-1274767896157.log
`-- data
    |-- Keyspace1
    `-- system

4 directories, 1 file

ターミナル上から接続してみる。

$ cassandra-cli --host localhost --port 9160
Connected to: "Test Cluster" on localhost/9160
Welcome to cassandra CLI.

Type 'help' or '?' for help. Type 'quit' or 'exit' to quit.
cassandra> 

データを投入し、データ内容を確認してみる。

cassandra> set Keyspace1.Standard2['miyazakiaoi']['first'] = 'Aoi'
Value inserted.
cassandra> set Keyspace1.Standard2['miyazakiaoi']['last'] = 'Miyazaki'
Value inserted.
cassandra> set Keyspace1.Standard2['miyazakiaoi']['age'] = '24'
Value inserted.
cassandra> get Keyspace1.Standard2['miyazakiaoi']
=> (column=last, value=Miyazaki, timestamp=1274774842755000)
=> (column=first, value=Aoi, timestamp=1274774820478000)
=> (column=age, value=24, timestamp=1274774879282000)
Returned 3 results.

README.txtで書かれている内容そのままだけど、データの登録、確認は、こんな感じらしい。