| Oracle Fusion Middleware Oracle Identity Managementアプリケーション開発者ガイド 11gリリース1(11.1.1) B56242-01 | 
 | 
|  戻る |  次へ | 
この章では、標準のディレクトリAPIにJavaの拡張機能を使用して、第3章で紹介した多くの操作を実行する方法について説明します。この章では使用例を示します。標準APIに対するOracleの拡張機能の詳細は、『Oracle Fusion Middleware Java API Reference for Oracle Internet Directory』を参照してください。
この章の項目は次のとおりです。
サンプル・コードは次のURLで入手できます。
http://www.oracle.com/technology/sample_code/
「Sample Applications–Oracle Application Server」の下の「Oracle Identity Management」リンクを探してください。
Java拡張機能は、LDAPクライアントのインストール時に標準のJava APIとともにインストールされます。APIとその拡張機能は、$ORACLE_HOME/jlib/ldapjclnt10.jarにあります。
Javaでは、LDAPエンティティ(ユーザー、グループ、レルム、アプリケーション)は、ハンドルではなくJavaオブジェクトとしてモデル化されます。このモデル化は、oracle.java.utilパッケージで行われます。他のすべてのユーティリィティ機能は、個々のオブジェクトとして(GUIDなど)、あるいはユーティリィティ・クラスの静的メンバー関数としてモデル化されます。
たとえば、ユーザーを認証するには、アプリケーションは次の手順に従います。
指定されたユーザー識別名で、oracle.ldap.util.Userオブジェクトを作成します。
必要なプロパティのすべてを備えたDirContext JNDIオブジェクトを作成するか、あるいはDirContextオブジェクトのプールからJNDIオブジェクトを取得します。
User.authenticateUserメソッドを呼び出して、DirContextオブジェクトおよびユーザー資格証明への参照を渡します。
既存のDirContextオブジェクトのプールから取得したDirContextオブジェクトは、そのプールに戻します。
CやPL/SQLのプログラマとは異なり、Javaプログラマはオブジェクトを明示的に解放する必要がありません。このタスクは、Javaのガベージ・コレクション・メカニズムが実行します。
Userクラス、SubscriberクラスおよびGroupクラスのほとんどのメソッドは、PropertySetCollectionオブジェクトを戻します。このオブジェクトは、1つ以上のLDAPエントリの集合を表しています。各エントリはPropertySetオブジェクトで表され、識別名で識別されます。PropertySetには、Propertyとして表される属性が含まれる場合があります。Propertyとは、そのPropertyが表す特定の属性に関する1つ以上の値の集合です。次に、これらのクラスの使用例を示します。
PropertySetCollection psc = Util.getGroupMembership( ctx,
                                                     myuser,
                                                     null,
                                                     true );
    // for loop to go through each PropertySet
    for (int i = 0; i < psc.size(); i++ ) {
    PropertySet ps = psc.getPropertySet(i);
   // Print the DN of each PropertySet
   System.out.println("dn:  " + ps .getDN());
   // Get the values for the "objectclass" Property
   Property objectclass = ps.getProperty( "objectclass" );
   // for loop to go through each value of Property "objectclass"
   for (int j = 0; j< objectclass.size(); j++) {
       // Print each "objectclass" value
       System.out.println("objectclass:  " + objectclass.getValue(j));
   }
}
エンティティmyuserは、Userオブジェクトです。pscオブジェクトには、myuserが属するネストされたグループがすべて含まれます。このコードは結果エントリをループし、各エントリのオブジェクト・クラス値をすべて出力します。
ユーザー関連機能はすべてoracle.ldap.util.UserというJavaクラスで抽象化されます。このプロセスは、次のようになります。
識別名、GUIDまたは単純な名前に基づいて、oracle.ldap.util.Userオブジェクトを構成します。
必要な場合は、User.authenticateUser(DirContext, int, Object)を呼び出して、ユーザーを認証します。
User.getProperties(DirContext)を呼び出して、ユーザー・エントリの属性を取得します。
User.getExtendedProperties(DirContext, int, String[])を呼び出して、ユーザーの拡張プロパティを取得します。intは、共有またはアプリケーション固有です。String[]は、希望するプロパティのタイプを示すオブジェクトです。String[]がNULLの場合は、指定したカテゴリの全プロパティが取得されます。
PropertySetCollection.getProperties(int)を呼び出して、手順4で戻されたプロパティの解析に必要なメタデータを取得します。
拡張プロパティを解析し、アプリケーション固有のロジックを続行します。この解析は、アプリケーション固有のロジックによっても行われます。
ユーザー認証は、ユーザーがログイン時に指定した資格証明とそのユーザーのディレクトリ内の資格証明を比較する一般的なLDAP操作です。Oracle Internet Directoryでは、次のものがサポートされています。
認証時に使用可能な任意の属性。
認証メソッドによって戻される任意のパスワード・ポリシー例外。ただし、パスワード・ポリシーはuserpassword属性のみに適用されることに注意してください。
次に、APIを使用してユーザーを認証するためのコード例を示します。
 // User user1 - is a valid User Object
        try
        {
                user1.authenticateUser(ctx,
                    User.CREDTYPE_PASSWD, "welcome");
                // or
                // user1.authenticateUser(ctx, <any
attribute>, <attribute value>);
        }
        catch (UtilException ue)
        {
                // Handle the password policy error
accordingly
                if (ue instanceof PasswordExpiredException)
                        // do something
                else if (ue instanceof GraceLoginException)
                        // do something
        }
subscriberクラスによってcreateUser()メソッドが使用され、プログラムによりユーザーが作成されます。ユーザー・エントリに必要なオブジェクト・クラスは、Oracle Delegated Administration Servicesを介して設定可能です。createUser()メソッドは、ユーザーの作成時に、クライアントが要件を理解し必須の属性に対して値を提供することを前提にしています。プログラマによって必須情報が提供されない場合、サーバーはエラーを戻します。
コード例の次のスニペットは、使用方法を示します。
// Subscriber sub is a valid Subscriber object // DirContext ctx is a valid DirContext // Create ModPropertySet object to define all the attributes and their values. ModPropertySet mps = new ModPropertySet(); mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"cn", "Anika"); mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"sn", "Anika"); mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"mail", "Anika@example.com"); // Create user by specifying the nickname and the ModPropertySet just defined User newUser = sub.createUser( ctx, mps, true); // Print the newly created user DN System.out.println( newUser.getDN(ctx) ); // Perform other operations with this new user
subscriberクラスによってgetUser()メソッドが提供され、Userクラスのパブリック・コンストラクタと置き換えられます。このメソッドは、指定された情報に基づいてUserオブジェクトを戻します。
次に、使用方法を示します。
// DirContext ctx is contains a valid directory connection with sufficient privilege to perform the operations // Creating RootOracleContext object RootOracleContext roc = new RootOracleContext(ctx); // Obtain a Subscriber object representing the default subscriber Subscriber sub = roc.getSubscriber(ctx, Util.IDTYPE_DEFAULT, null, null); // Obtain a User object representing the user whose nickname is "Anika" User user1 = sub.getUser(ctx, Util.IDTYPE_SIMPLE, "Anika", null); // Do work with this user The getUser() method can retrieve users based on DN, GUID and simple name. A getUsers() method is also available to perform a filtered search to return more than one user at a time. The returned object is an array of User objects. For example, // Obtain an array of User object where the user's nickname starts with "Ani" User[] userArr = sub.getUsers(ctx, Util.IDTYPE_SIMPLE, "Ani", null); // Do work with the User array
この項では、Java APIを使用してアイデンティティ管理レルムのオブジェクトを取得する方法について説明します。
RootOracleContextクラスはルートOracleコンテキストを表します。アイデンティティ管理レルムの作成に必要な情報のほとんどは、ルートOracleコンテキストに格納されています。RootOracleContextクラスではgetSubscriber()メソッドが提供されます。このメソッドは、subscriberクラスのパブリック・コンストラクタと置き換えられ、指定された情報に基づいてアイデンティティ管理レルム・オブジェクトを戻します。
次に、使用方法を示します。
// DirContext ctx contains a valid directory // connection with sufficient privilege to perform the // operations // Creating RootOracleContext object RootOracleContext roc = new RootOracleContext(ctx); // Obtain a Subscriber object representing the // Subscriber with simple name "Oracle" Subscriber sub = roc.getSubscriber(ctx, Util.IDTYPE_SIMPLE, "Oracle", null); // Do work with the Subscriber object
次の例では、単純な名前、GUIDまたはDNがわかっている場合にユーザーのログイン名を検索する方法を示します。Oracle Single Sign-Onのログイン名は、ニックネームとも呼ばれます。
この例は、2つの部分から構成されています。
このレルムへのニックネームの保存に使用されている属性を確認します。
ユーザー・オブジェクトを取得し、ニックネーム属性の値を確認します。
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.io.*;
public class NickNameSearch {
   public static void main(String[] args)
      throws Exception
   {
      InitialLdapContext ctx = ConnectionUtil.getDefaultDirCtx( args[0],
                                     args[1], args[2],args[3]);
      RootOracleContext roc=new RootOracleContext(ctx);
      Subscriber sub = null;
      sub = roc.getSubscriber(ctx, Util.IDTYPE_DEFAULT, null, null) ;
      PropertySetCollection psc = sub.getProperties(ctx,
                                     Subscriber.USER_NAMING_PROPERTIES, null);
      String nickNameAttribute = null;
      try
      {
          nickNameAttribute = (String) psc.getPropertySet(0)
.getProperty(Subscriber.USER_NAMING_ATTR_SIMPLE).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute name
         System.exit(0);
      }
      System.out.println("Nickname attribute: " + nickNameAttribute);
      // Retrieve user using simple name, guid or DN
      User user = sub.getUser(ctx, Util.IDTYPE_SIMPLE,"orcladmin", null);
      System.out.println("user DN: " + user.getDN(ctx));
      // Retrieve nickname value using User object
      psc = user.getProperties(ctx, new String[]{ nickNameAttribute });
      String nickName = null;
      try
      {
          nickName = (String) psc.getPropertySet(0).getProperty(nickNameAttribute).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute value
         System.exit(0);
      }
      System.out.println("Nickname : " + nickName);
   }
}
次の新しいJavaクラス(パブリック・クラス)が導入されました。
public class oracle.ldap.util.discovery.DiscoveryHelper
このクラスでは、指定されたソースから特定の情報を検出するメソッドが提供されます。
表5-1 ディレクトリ・サーバー検出のメソッド
| メソッド | 説明 | 
|---|---|
| discover | 指定されたソースから特定の情報を検出します。 | 
| setProperty | 検出に必要なプロパティを設定します。 | 
| getProperty | プロパティの値にアクセスします。 | 
既存のJavaクラスoracle.ldap.util.jndi.ConnectionUtilに、次の2つの新しいメソッドが追加されます。
getDefaultDirCtx: オーバーロードされたこのファンクションでは、oracle.ldap.util.discovery.DiscoveryHelper.discover()に対して内部コールを実行して、SSL以外のLDAPサーバーのホスト名およびポート情報が判断されます。
getSSLDirCtx: オーバーロードされたこのファンクションでは、oracle.ldap.util.discovery.DiscoveryHelper.discover()に対して内部コールを実行して、SSLのLDAPサーバーのホスト名およびポート情報が判断されます。
次に、ディレクトリ・サーバー検出に使用するJavaプログラムの例を示します。
import java.util.*;
import java.lang.*;
import oracle.ldap.util.discovery.*;
import oracle.ldap.util.jndi.*;
public class dsdtest
{
  public static void main(String s[]) throws Exception
  {
    HashMap reshdl = new HashMap();
    String result = new String();
    Object resultObj = new Object();
    DiscoveryHelper disco = new
DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);
// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com")
;
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD,
   DiscoveryHelper.USE_INPUT_DN_METHOD);
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");
// Call the discover method
int res=disco.discover(reshdl);
if (res!=0)
   System.out.println("Error Code returned by the discover method is :"+res) ;
// Print the results
printReshdl(reshdl);
}
public static void printReshdl(HashMap reshdl)
{
  ArrayList result = (ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
if (result != null)
{
  if (result.size() == 0) return;
  System.out.println("The hostnames are :-");
  for (int i = 0; i< result.size();i++)
  {
      String host = (String)result.get(i);
      System.out.println((i+1)+".
'"+host+"'");
   }
  }
 }
}
JNDIを使用してSASL接続を確立する場合、javax.naming.Contextの次のプロパティを設定する必要があります。
Context.SECURITY_AUTHENTICATIONに「DIGEST-MD5」を設定します。
Context.SECURITY_PRINCIPAL
後者にはプリンシパル名を設定します。この名前は、サーバー固有の形式です。次のいずれかのようになります。
認証されているエンティティの完全に修飾された識別名が続く識別名dn:
ユーザー識別子が続く文字列u:
Oracleディレクトリ・サーバーは、完全に修飾された識別名(cn=user,ou=my department,o=my companyなど)のみを受け入れます。
| 注意:SASL識別名は、SASLバインドをコールするAPIに渡される前に正規化される必要があります。SASLベリファイアを生成するために、Oracle Internet Directoryでは正規化された識別名のみがサポートされます。 | 
次のコードでは、SASL Digest-MD5を使用したJava LDAP/JNDIの例を示します。
/* $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $ */
/* Copyright (c) 2003, 2005, Oracle. All rights reserved.  */
/*
  DESCRIPTION
   <short description of component this file declares/defines>
  PRIVATE CLASSES
   <list of private classes defined - with one-line descriptions>
  NOTES
   <other useful comments, qualifications, and so on.>
  MODIFIED    (MM/DD/YY)
   qdinh       04/23/03 - Creation
*/
/**
*  @version $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $
*  @author  qdinh   *  @since   release specific (what release of product did this appear in)
*/
package oracle.ldap.util.jndi;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.lang.*;
import java.util.*;
public class LdapSasl
{
   public static void main( String[] args)
       throws Exception
   {
    int numofargs;
    numofargs = args.length;
    Hashtable hashtable = new Hashtable();
    // Look through System Properties for Context Factory if it is available
    // then set the CONTEXT factory only if it has not been set
    // in the environment -
    // set default to com.sun.jndi.ldap.LdapCtxFactory
    hashtable.put(Context.INITIAL_CONTEXT_FACTORY,
          "com.sun.jndi.ldap.LdapCtxFactory");
    // possible valid arguments
    // args[0] - hostname
    // args[1] - port number
    // args[2] - Entry DN
    // args[3] - Entry Password
    // args[4] - QoP [ auth | auth-int | auth-conf ]
    // args[5] - SASL Realm
    // args[6] - Cipher Choice
    //    If QoP == "auth-conf" then args[6] cipher choice can be
    //     - des
    //     - 3des
    //     - rc4
    //     - rc4-56
    //     - rc4-40
    hashtable.put(Context.PROVIDER_URL, "ldap://"+args[0]+":"+args[1]);
        hashtable.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
    System.out.println("hash put security dn: " + args[2]);
    hashtable.put(Context.SECURITY_PRINCIPAL, args[2] );
    hashtable.put(Context.SECURITY_CREDENTIALS, args[3] );
    // For Quality of Protection modes
    // 1. Authentication and Data Integrity Mode - "auth-int"
    // 2. Authentication and Data Confidentiality Mode  "auth-conf"
    //
    // hashtable.put("javax.security.sasl.qop",args[4]);
    hashtable.put("javax.naming.security.sasl.realm", args[5]);
    // Setup Quality of Protection
    //
    // System.out.println("hash sasl.qop: " + args[4]);
    hashtable.put("javax.security.sasl.qop",args[4]);
    if (numofargs > 4)
    {
    if (args[4].equalsIgnoreCase("AUTH-CONF"))
    {
        //  Setup a cipher choice only if QoP == "auth-conf"
        String strength = "high";
        String cipher = new String(args[6]);
                if (cipher.compareToIgnoreCase("rc4-40") == 0)
        strength = "low";
        else if (cipher.compareToIgnoreCase("rc4-56") == 0 ||
             cipher.compareToIgnoreCase("des")== 0 )
        strength = "medium";
        else if (cipher.compareToIgnoreCase("3des") == 0 ||
             cipher.compareToIgnoreCase("rc4") == 0)
        strength = "high";
        // setup cipher choice
        System.out.println("hash sasl.strength:"+strength);
        hashtable.put("javax.security.sasl.strength",strength);
    }
    // set maxbuffer length if necessary
    if (numofargs > 7 && !"".equals(args[6]))
        hashtable.put("javax.security.sasl.maxbuf", args[5].toString());
    }
    // Enable Debug --
    // hashtable.put("com.sun.jndi.ldap.trace.ber", System.err);
    LdapContext ctx = new InitialLdapContext(hashtable,null);
    // At this stage - SASL Digest -MD5 has been successfully
    System.out.println("sasl bind successful");
    // Ldap Search Scope Options
    //
    // - Search base - OBJECT_SCOPE
    // - One Level   - ONELEVEL_SCOPE
    // - Sub Tree    - SUBTREE_SCOPE
    //
        // Doing an LDAP Search
    PropertySetCollection psc = Util.ldapSearch(ctx,"o=oracle,dc=com","objectclass=*",SearchControls.OBJECT_SCOPE,
                           new String[] {"*"});
      // Print out the serach result
    Util.printResults(psc);
    System.exit(0);
 }                                                              }