Monday, September 9, 2013

JBoss AS 7.1+'de MySQL Veritabanı kullanarak Kimlik Doğrulama

Java EE platformu kullanılarak kurumsal uygulama geliştirirken tasarımda düşünülmesi gereken bileşenlerden biri de güvenliktir. Bu amaçla Java EE platformunun rol tabanlı güvenlik modelinden yararlanılır. Buna göre kaynaklar ile bu kaynaklara erişim yetkisi olan roller ilişkilendirilir. Roller ile kullanıcılar arasındaki bağlantı ise Java EE bağlamı dışında düşünülür. Kullanıcı bilgileri genellikle veritabanı ya da LDAP gibi bir dizin sunucusunda saklanılır ve kimlik doğrulama işlemi bu sunuculara ihale edilir. JBoss AS 7 Java EE 6 uyumlu, açık kaynak kodlu, Red Hat firmasından desteğini alabileceğiniz, modüler bir mimariye sahip, çevik bir uygulama sunucusudur.  JBoss AS 7.2 sürümü ile kısa bir süre önce Red Hat yazılım ürününe dönüşmüştür ve EAP (=Enterprise Application Platform) olarak yayınlanmaktadır. Güncel sürümünü (JBoss EAP 6.1) bu adresten indirebilirsiniz. Kurulum için tek yapmanız gereken sıkıştırılmış arşiv dosyasını uygun bir dizine açmaktır. Bağımsız ve alan olmak üzere iki farklı kipte kullanabilirsiniz. Bağımsız kipte çalıştırmak için standalone.bat (standalone.sh) betiğini ve alan kipinde çalıştırmak için domain.bat (domain.sh) betiğini kullanıyoruz. Betikleri çalıştırmadan önce iki sistem değişkenine atama yapmanız gerekir:
c:\opt\jboss-eap-6.1>set JAVA_HOME=c:\opt64\java\jdk1.7.0_25
c:\opt\jboss-eap-6.1>set JBOSS_HOME=c:\opt\jboss-eap-6.1

c:\opt\jboss-eap-6.1>set PATH=%JAVA_HOME%\bin;%JBOSS_HOME%\bin;%PATH%
Bundan sonra betiklerden birini kullanarak sunucuyu bağımsız ya da alan kipinde çalıştırabilirsiniz:

Bağımsız kipte çalıştırıldığında varsayılan yapılandırma dosyası standalone.xml ve alan kipinde çalıştırıldığında varsayılan yapılandırma dosyası ise domain.xml ve host.xml dosyalarıdır. Kimlik doğrulama ile ilgili tanımlamalar hangi kipte sunucuyu kullandığınıza göre standalone.xml ya da domain.xml dosyasında aynı şekilde yapılmaktadır.

Kimlik Doğrulama için İlişkisel Veritabanı Sunucusu Kullanımı

Bu örnek yapılandırmada MySQL 5.6 veritabanını kullanacağız. Öncelikli olarak bir veritabanı ve bu veritabanında iki adet tablo yaratacağız:

mysql> create database userdb;
Query OK, 1 row affected (0.00 sec)

mysql> use userdb;
Database changed
mysql> CREATE TABLE USERS(
    ->    login VARCHAR(64) PRIMARY KEY,
    ->    passwd VARCHAR(64)
    -> ) engine=InnoDB;
Query OK, 0 rows affected (0.32 sec)

mysql> CREATE TABLE USER_ROLES(
    ->    login VARCHAR(64),
    ->    role VARCHAR(32)
    -> ) engine=InnoDB;
Query OK, 0 rows affected (0.38 sec)
Veritabanında USERS tablosunda kullanıcı adı ve parolası ve USER_ROLES tablosunda ise rol ve kullanıcı ilişkileri saklanmaktadır. Örnek bir kullanıcı ve rol ekleyelim:
mysql> INSERT into USERS values('jackb','Xr4ilOzQ4PCOq3aQ0qbuaQ==');
Query OK, 1 row affected (0.07 sec)

mysql> INSERT into USER_ROLES values('jackb', 'WEB_USER');

Query OK, 1 row affected (0.04 sec)
Veritabanında parolanın kendisini değil MD5 ile elde edilmiş özetini ve Base64 ile kodlanmış değerini saklıyoruz. Bu kodlanmış değeri elde etmek için aşağıdaki komutu kullanabilirsiniz:
$ echo -n secret | openssl dgst -md5 -binary | openssl base64
Xr4ilOzQ4PCOq3aQ0qbuaQ==
Şimdi artık standalone.xml yapılandırma dosyasında kimlik doğrulama için gerekli tanımlamaları yapabiliriz:
<?xml version='1.0' encoding='UTF-8'?>
<server xmlns="urn:jboss:domain:1.4">
      .
      .
      .
       <subsystem xmlns="urn:jboss:domain:datasources:1.1">
            <datasources>
               .
               .
               .
               <datasource jta="true" jndi-name="java:/usersDS" pool-name="userdb_pool" enabled="true" 
                        use-java-context="true" use-ccm="true">
                    <connection-url>jdbc:mysql://localhost:3306/userdb</connection-url>
                    <driver>mysql</driver>
                    <pool>
                        <min-pool-size>1</min-pool-size>
                        <max-pool-size>5</max-pool-size>
                        <prefill>true</prefill>
                        <use-strict-min>true</use-strict-min>
                    </pool>
                    <security>
                        <user-name>root</user-name>
                        <password>root</password>
                    </security>
                    <timeout>
                        <idle-timeout-minutes>0</idle-timeout-minutes>
                        <query-timeout>600</query-timeout>
                    </timeout>
                    <statement>
                        <track-statements>true</track-statements>
                        <prepared-statement-cache-size>2</prepared-statement-cache-size>
                        <share-prepared-statements>true</share-prepared-statements>
                    </statement>
                </datasource>
            </datasources>
        </subsystem>
        .
        .
        .
        <subsystem xmlns="urn:jboss:domain:security:1.2">
            <security-domains>
                <security-domain name="database" cache-type="default">
                    <authentication>
                        <login-module code="Database" flag="required">
                            <module-option name="dsJndiName" value="java:/usersDS"/>
                            <module-option name="principalsQuery" value="select passwd from USERS where login=?"/>
                            <module-option name="rolesQuery" value="select role, 'Roles' from USER_ROLES where login=?"/>
                            <module-option name="hashAlgorithm" value="MD5"/>
                            <module-option name="hashEncoding" value="BASE64"/>
                        </login-module>
                    </authentication>
                </security-domain>
                .
                .
                .
            </security-domains>

        </subsystem>

        .
        .
        .
</server>
Bir kurumsal uygulamanın bu bu yapılandırmadan yararlanabilmesi için standart dağıtım yapılandırma dosyası web.xml'de aşağıdaki gibi bir kısıtlama tanımı yapılmalıdır.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>HtmlAuth</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>WEB_USER_ROLE</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Database</realm-name>
</login-config>
<security-role>
<role-name>WEB_USER_ROLE</role-name>
</security-role>
</web-app>
Son olarak uygulama rolü ile veritabanında tanımlanan rol arasında mutlaka aşağıdaki gibi bir eşleme yapılması gerekmektedir. Bu eşleştirmeyi JBoss uygulama sunucusuna özel yapılandırma dosyasında, jboss-web.xml,  yapıyoruz:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web> 
  <context-root>/game</context-root>
  <security-domain>java:/jaas/database</security-domain>
  <security-role>
      <role-name>WEB_USER</role-name>
      <principal-name>WEB_USER_ROLE</principal-name>
  </security-role>
</jboss-web>