2006年02月10日





2005年09月25日

WebLogic平台的Web SSO(SAML)解决方案

时间:2005-07-04

作者:马晓强

浏览次数: 1030

本文关键字:


文章工具

推荐给朋友 推荐给朋友

打印文章 打印文章

SSO(Single Sign-On)即所谓的单点登录。用户在一处登录后访问其他网站时不需要再次输入用户名和口令,即可完成身份验证。

  文章《体验WebLogic Server 8.1 SP4新增功能之WebLogic Single Sign-On》(http://dev2dev.bea.com.cn/techdoc/200507499.html) 中介绍了使用WLS8.1 SP4版本中的Single Pass Negotiate Identity Assertion Provider完成与Windows平台的SSO。但有更多的人可能希望在不借助,或者不与Windows集成的情况下完成Single Sign-On。Kerberos当然可以是其中的一种解决办法,但是目前互联网上应用更多的是SAML,一个用于在网络实体间交换安全认证信息的基于 XML的框架。

  本文据此提出一种适用(针对)于WebLogic Server的,简单、可行的SSO解决方案。这个方案以集中统一的用户信息为基础,但不包括通常理解的权限管理,而仅仅提供一个身份验证的服务。因为一般情况下,一个企业内部的多个成熟系统通常分别有自己的已经比较完善的用户身份验证和权限管理功能。在这种情况下,为整合多个业务系统而提供包括权限管理在内的多种安全服务,常常将问题复杂化(尽管SAML可以做到这一点)。

  因此本文提出的方案将只解决用户的身份验证,即实现SSO的本义。在SSO帮助用户完成身份验证后,由各个业务系统本身的权限管理进行用户行为的进一步控制。这样不仅完成了用户帐号的集中管理(SAML可以完成不同系统间不同帐号的federated但不在本文讨论范围内),又不失原有系统灵活的权限控制。而且方案简单可行,不需要对原有应用做较大更改,适合快速解决Single Sign-On问题。

  如果有更复杂的需求,完全可以在本文的基础上,参考Shibboleth(http://shibboleth.internet2.edu/)项目以及SourceID(http://www.sourceid.org/index.html)的项目进行深入的研究和了解,以找出最适合自己的解决方案。

名词

SAML

  本文将以SAML 1.1实现SSO。SAML定义了一个用于在线商业系统间交换安全信息的基于XML的框架,它由OASIS (the Organization for the Advancement of Structured Information Standards)组织的Security Services Technical Committee (SSTC)开发。详情参考文章后面的参考资料部分。

OpenSAML

  一个开源的SAML1.1实现,本文使用opensaml1.1完成与SAML相关的逻辑处理。OpenSAML是Shibboleth项目的一部分。Shibboleth是一个针对SSO的开源项目。

WebLogic Server

  业界领先的J2EE应用服务器。本文的方案以WebLogic Server 8.1SP4为基础。本文附带的Demo应用只能跑在WLS8.1 SP4上,如果8.1SP3等版本需要适当改动。

Identity Assertion Provider

  Identity Assertion Provider是WebLogic 7以后提供的众多Provider的一种,它其实就是一个Authentication Provider,只不过它不需要口令来完成用户的身份验证;如果在其他平台比如Tomcat上实现,也可以是一个普通的LoginModule,只需要通过CallbackHandler获取Token然后验证就可以了。

  本文附带一个示例的Identity Assertion Provider。

Java KeyStore

  本文将附带一个自签名的java key store,它由JDK带的Keytool生成并签名。

Service Provide

  服务提供者。就是我们一般理解的业务系统,它通过配置在其上的Identity Assertion Provider完成对用户提交Token的校验,一般又称为SAML Assertion Consumer。文章后面简称为SP。

Identity Provider

  身份认证提供者。通过它对用户进行身份验证,以及生成SAML Assertion Token,又称为SAML Assertion Productor。本方案的实现中核心为一个Servlet。文章后面简称为IDP。

Use Case

  本文描述的方案实现了SAML 1.1 提供的POST Profile User Case,并有适当修改。

*

用户打开浏览器访问Service Provider 网站,访问受SAML Auth Filter保护的页面
*

SP网站的SAML Auth Filter 检查到用户没有登录,那么将用户请求的页面地址(TARGET)附加在IDP的URI之后,并将用户的浏览器重定向到IDP网站
*

否则SP网站接受用户请求

*

IDP网站接受到用户请求,判断用户是否已经登录
*

如果用户已经在IDP登录,那么到10
*

如果用户没有在IDP登录,那么向用户响应登录表单
*

用户通过IDP传回的登录表单,输入用户名和口令并提交登录请求
*

IDP接受到用户登录请求,使用用户提交的用户名和口令进行身份验证
*

如果验证失败,向用户响应登录失败页面

*

如果登录成功,并且提交的Query String中指定了TARGET,那么会向用户响应一个自动提交表单,将SAML Assertion Token提交到TARGET指定的URL

*

SP网站接受到用户提交的SAML Assertion Token,并将Token传递给Identity Assertion Provider
*

Identity Assertion Provider校验Token是否合法,并从中读取用户信息
*

如果Token通过验证,Identity Assertion Provider返回经过验证的Subject,否则抛出验证异常
*

SP获取到Identity Assertion Provider返回的Subject,表示用户登录成功,返回用户请求的页面
*

否则SP获取到Identity Assertion Provider抛出的LoginException,向用户响应登录失败页面,用户登录失败

技术实现

  这里描述一下前面Use Case中涉及的几个技术方面。

*

从安全角度考虑,用户到IDP和SP间的连接必须通过HTTPS,尤其是在外网Internet;对于内部网络Intranet应用可以通过其他办法强化网络安全

*

使用SAML Auth Filter控制哪些页面加入SSO

<filter-mapping>

<filter-name>SAMLAuthFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

  这里表示SP全部的页面受SAMLAuthFilter保护。

*

IDP根据用户提交的帐号和口令进行身份验证

  我们使用 WebLogic提供的 API进行用户身份验证,这样才能完成一个让 WebLogic Server认为是合法的登录。这个weblogic.servlet.security.ServletAuthentication提供的方法具体实现在不同的SP版本中总有变化,比如WLS8.1 SP3和8.1 SP4,因此需要留意这一点。本文方案的实现,以WELS8.1SP4为准。

public static int login(java.lang.String username,

java.lang.String password,

javax.servlet.http.HttpServletRequest request)

throws javax.security.auth.login.LoginException

Returns an int value for AUTHENTICATED or FAILED_AUTHENTICATION after using the username and password to authenticate the user and setting that user information into the session. This method is similar to "weak", except that the LoginException is propogated to caller.

Parameters:

username – String

password – String

request – HttpServletRequest

Returns:

int authentication value

Throws:

javax.security.auth.login.LoginException -

*

IDP根据用户信息生成相应的SAML Assertion Token

这里的代码来自于opensaml提供的POSTProfileTest.java,用于生成 SAMLResponse并进行签名

SAMLResponse r = SAMLPOSTProfile.prepare(

"www.opensaml.org",

"www.opensaml.org",

Collections.singleton("http://www.opensaml.org"),

"foo",

"foo",

null,

"127.0.0.1",

"foo",

new Date(),

Collections.singleton(

new SAMLAuthorityBinding(SAMLBinding.SAML_SOAP_HTTPS,

"http://www.opensaml.org",

new QName(XML.SAMLP_NS,"AttributeQuery")

)

)

);

assertNotNull("No SAMLResponse was generated.",r);

Iterator i = r.getAssertions();

((SAMLAssertion)i.next()).sign(

XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,

ks.getKey(alias,password),

Arrays.asList(ks.getCertificateChain(alias))

);

r.sign(

XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,

ks.getKey(alias,password),

Arrays.asList(ks.getCertificateChain(alias))

);

*

Identity Assertion Provider校验IDP生成的Token

  具体Identity Assertion Provider的实现超出了本文讨论的篇幅。这里只描述其需要实现的主要逻辑,同样来自于POSTProfileTest.java

assertTrue("SAMLResponse is not signed.",r.isSigned());

System.err.println("================ Generated Response ===============");

r.toStream(System.err);

System.err.println();

r.verify(ks.getCertificate(alias));

SAMLResponse r2 = SAMLPOSTProfile.accept(r.toBase64(), "www.opensaml.org", 60, true);

assertTrue("SAMLResponse is not signed.",r2.isSigned());

SAMLPOSTProfile.getSSOAssertion(r2,Collections.singleton("http://www.opensaml.org")).verify(ks.getCertificate(alias));

r2.verify(ks.getCertificate(alias));

System.err.println("================ Verified Response ===============");

r2.toStream(System.err);

System.err.println();



  只要将上面的逻辑放入在Identity Assertion Provider中就可以了。

*

自动提交表单

  在IDP响应给用户的页面包含了一个自动提交的表单,将SAML Assertion Token通过HTTP POST提交给用户请求的SP页面。这部分由SAML1.1中的Browser/POST Profile定义。由于生成的SAML Assertion往往比较大,不能通过HTTP GET提交,因此通过自动提交表单完成。这样用户仍然可能会感受到短暂的跳转,如果使用Browser/Artifact Profile,那么将由SP和IDP进行沟通,用户感受会好一点,但是开发,部署均麻烦一些,SP和IDP需要双向SSL,并且opensaml没有提供这个实现,这里就不深入讨论了。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<html>

<head>

<title>Auto Submit</title>

</head>

<body onLoad="document.myform.submit()">

<form name="myform" action="">

</form>

</body>

</html>

  综上,大家看是不是很简单呢?J

Demo的部署和演示

  这里介绍附带的几个文件

sp.war

  Service Provider应用,可以直接部署在WebLogic Server上。

idp.war

  Identity Provider应用。可以直接部署在WebLogic Server上。其中主要就是一个LogonServlet

samlIdentityProvider.jar

  这里提供的SAML Identity Assertion Provider只是为了演示使用,如果需要应用在具体的生产环境中,则需要详尽的测试,调优,以及适当的修改。

opensaml.jar

  运行OpenSAML需要的jar包,同时它使用了很多第三方的类库,因此这些第三方的jar包也需要,由于文件太大,不在附件中,大家可以去www.opensaml.org下载最新版本。

xbean.jar

  包含在WLS8 /server/lib目录下,需要在启动WLS的脚本中加入到classpath中

endorsed

  OpenSAML要求使用的XML Parser,在附件中

idp.jks

  使用keytool生成的KeyStore,存放了一对密钥

idp.cer

  密钥对中的公钥,SP使用它校验Token是否有效

  下面介绍Demo的部署过程。

*

解开附件的压缩包,将opensaml.jar以及其使用到的第三方jar包和xbean.jar放在适当地方;将endorsed目录放在适当地方,将在2步骤中使用
*

修改启动WebLogic的脚本,在CLASSPATH中增加指向opensaml.jar以及其第三方jar和xbean.jar(WebLogic8中也带有该jar)的路径,并设置系统变量-Djava.endorsed.dirs=<endorsed目录>
*

为验证SSO需要将sp.war和idp.war分别部署在两台WebLogic Server上。修改idp.war/WEB-INF/web.xml中在path参数中指明idp.jks的文件路径,以及访问keystore的口令 123456(这里keystore口令和alias的主口令设置为一致,否则此处需要多设置一个配置项);修改sp.war/WEB- INF/web.xml,在redirectURL参数配置IDP网站的地址,指向SAMLLogon 这个Servlet在IDP上映射的URL。
*

在SP上配置SAML Identity Assertion Provider(IDP所在的WLS不需要配置)
o

将samlSecurityProvider.jar 拷贝至 /server/lib/mbeantypes下。如果有Managed Server并且Managed Server在另外一台物理机器上或另外一个独立的WL安装目录下,那么同样需要将samlSecurityProvider.jar拷贝至对应的 mbeantypes目录下
o

重新启动全部的Server
o

通过WebLogic Console配置SAML Identity Assertion Provider,在Detail中指明idp.cer证书的路径,别名,以及口令。需要注意一点就是,需要将Base64的选择取消
o

重新启动全部的WebLogic Server
*

在SP 和IDP两个系统的WebLogic Server Realm中增加一个测试用户,为sso_user并设置口令,如果SP和IDP部署在同一个WLS Domain,那在WLS Admin Console上做一次就可以了;如果有统一的用户存储,那么部署对应的Authentication Provider就可以了

  至此,部署成功。

下面是演示过程:

演示一:

*

访问SP网站的受保护页面http://localhost:19001/sp/index.jsp
*

浏览器被重定向到IDP网站被要求登录

*

输入用户sso_user以及用户口令登录
*

登录成功后浏览器返回 http://localhost:19001/sp/index.jsp页面内容

演示二:

*

访问IDP网站的登录页面 http://localhost:18000/logon
*

在登录表单中输入用户名sso_user和口令

*

登录成功后,显示IDP欢迎页面以及用户登录成功的帐号

*

手工在浏览器中输入地址 http://localhost:19001/sp/index.jsp
*

浏览器显示SP页面内容而不需要再登录



演示三(图片省略):

  如果IDP网站当机,那么只是丧失SSO而已,不会影响业务系统的使用,这一点对大的应用来说很重要。

*

访问SP的登录页面 http://localhost:19001/sp/logon.jsp
*

在登录表单中输入用户名sso_user和口令,进行登录
*

登录成功后,欢迎页面显示用户的帐号信息

参考资料

*

http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=securityOASIS关于SAML的站点
*

http://www.opensaml.orgOpenSAML的网站,它是一个叫Shibboleth项目的一部分。Shibboleth项目主要应用在校园内,以及校园间的应用系统的用户身份联合认证。也有不少商业和政府网站采用
*

http://www.sourceid.org/index.htmlSourceID 是非常有实力的一个开源组织,旗下有多个开源项目(SAML、Liberty Alliance,WS-Federation)。SSO是其主要目的之一,当然不仅限于此,更着重于用户身份的联合,以及安全信息的共享。比如用户在网站1的帐号是User1,在网站2的帐号是User 2,那么如何实现SSO呢?
*

http://e-docs.bea.com/wls/docs81/security/index.html更多关于开发WebLogic Security Provider的信息

示例程序

作者简介




马晓强是高级软件工程师,现在广东从事J2EE,LDAP相关的设计开发工作。对WebLogic,LDAP以及Single Sign-On等产品、技术很感兴趣。

2005年09月24日

http://sentom.net/list.asp?id=13

创刊号-Liberty


作者:jini 来源:java 公开原始码报
申明:未经作者同意,谢绝转载
网络越来越发达,相对的,网站也越来越多,提供个性化的服务也同步地增多。那么,要如何整合各个系统之间的认证,让系统可以达到单一登陆就可以尝试进入其他属于相同认证地系统呢,这问题因为没有标准之前,都让许多系统没有办法整合认证措施,所以 liberty 专案就是来解决这个问题的。

一、Liberty 联盟主要的目标为

Enable consumers to protect the privacy and security of their network identity information
Enable businesses to maintain and manage their customer relationships without third-party
Provide an open single sign-on standard that includes decentralized authentication and authorization from multiple providers
Create a network identity infrastructure that supports all current and emerging network access devices

二、liberty 建置后的例子

先假设TestA 属于 Indentity Provider 而 TestB 属于 Service Provider 。
当你达到一个 TestA 网站,她要求你登陆,如果你登陆成功,那就代表 testA 验证你的资料成功了,我们称之 <i><b>authenticated</b></i>。
接着 testA Identity Server 会询问你要不要使用 SSO ,属于同一个 Identity Federation 相关系统就可以自动登陆了,选择同意自动登陆。
当你去另外一个 TestB 网站,如果她属于同一个 Identity Federation ,她就会询问你是否使用在 testA 已经验证过的身份直接登陆(也可以设定不询问就直接登陆了)。
此时他会让你等待一下,因为 testB 正在和 testA 做验证资料交换,如果你在 testA 的验证记录还是 authenticated 那么 testB 系统将会让你进入。
如此一來使用者的感觉就像单一登陆(SSO)。

三、liberty 是由三个组件组合而成的

(1) Web redirection
Action that enables Liberty-enabled entities to provide
services via today’s user-agent-installed base.
(2) Web services
Prototcol profiles that enable Liberty-enabled entities to
directly communicate.
(3) Metadata and schemas
A common set of metadata and formats used by Liberty-enabled
sites to communicte various provider-specific and other
information.

首先来谈 Web redirection
基本上有几个方法可以做到 redirection
1.使用 HTTP-Redirect-Based Redirection(use status 302 and GET to identity server)
2.使用 Form-POST-Based Redirecton (use POST and javascript)
3.使用 Cookie( 但是 cookie 因为 domain 的限制所以不建议使用,不过如果是同一 domain 则可以使用 )

其次谈到 Web services
遵循的是 SOAP (now 1.1, 相关的 soap 请参阅 xml.apache.org base xml and http)
顺便回复 gary , 这有没有长度限制 我也不太清楚
因为我印象中没有这个条件规定 ( sorry )

最后 metadata and schemas
包含的就是 service provider and identity provider 之间传输的资料格式了
最基本具有 Account/Identity, Authentication Context,Provider Metadata,

sso 的原理就是
1. 当你到达一个 service provider 她会检查你是否已经 authenticated
2. 如果没有, service provider 将使用 http-redirect 或 form post 将网页导到 identity provider
3. 当你到达 indentity server 就会有登陆的地方
4. 执行登陆
5. identity server 将会把你导回你之前的 service provider 并且加上凭证
6. service provider 将会接受导来自identity server 的 redirect 并且 parse 凭证
7. service provider 将使用改凭证会回到 identity server 得到使用者资料

如果使用 cookie 在同一个 domain 就更简单了
1. 使用者直接到 identity server 取得认证 她将会将你导到 common domain
2. Common domain Service 将写 cookie 到你的电脑
3. 当你使用另外的 service provider site
4. service provider 将你导到 common domain
5. common domain service 将从 cookie 中取得 IDP list 并却加上 url 导回 service provider
6. 如果你还没有 login 则会要求你登陆

至于凭证资料的格式是什么样子呢 authentication context
我们将称之为 SAML
我列出范例 有兴趣的可以参阅 spec ( http://www.projectliberty.org/specs/liberty-architecture-authentication-context-v1.1.pdf )

<?xml version="1.0"?>
<saml:Assertion>
<saml:AuthenticationStatement AuthenticationMethod=" urn:ietf:rfc:2246">
<saml:Subject>
<saml:NameIdentifierFormat="http://www.oasis-open.org/committees/security/docs/cs-sstc-core-28#X509SubjectName">
cn=Joe User,dc=projectliberty,dc=org
</saml:NameIdentifier>
</saml:Subject>
</saml:AuthenticationStatement>
<saml:Advice>
<!–additional elements in separate namespace –>
</saml:Advice>
</saml:Assertion>


相关的 protocols 请参阅 protocols-schema ( 我也是从这里剪贴出来的 )
http://www.projectliberty.org/specs/liberty-architecture-protocols-schema-v1.1.pdf

至于 profile 应该如何去传递
请参阅 http://www.projectliberty.org/specs/liberty-architecture-bindings-profiles-v1.1.pdf

最后针对牛人们在讨论的 LDAP 存储资料问题
基本上 LDAP 不适合存放大量资料
在 clayton donley (manning)的书中第一章 (1.2)
就开宗名义的说
ldap is not a relational database,
is not a file system for very large objects,
is not optimal for very dynamic objects,
is not useful without applications
所以我的建议是
如果你要放置一些资料
就摆一些可能写在 session 中的小资料

至于 directory server authentication
Password 是否可以比较 use compare()
因为 directoy server 上面存储 user password 为纯粹的 text file
机会非常的少
所以呢不会使用取得 password property 再去比较

而是
先根据 username 取得 DN
尝试使用 DN and password 去 Open connection
回传 true / false;
不需要考虑她的编码方式

最后 LDAP 的工作则是 authorization
去检查是否具有使用的权限

http://www.javaworld.com/javaworld/jw-05-2002/jw-0524-signon.html

Participant interaction
Here is a brief description of how the pattern elements work:

When a gatekeeper intercepts a request to access a protected resource, it first checks to see if a login session for the user in that Web application is established. If not, the gatekeeper checks to see if a global SSO session is established with the authenticator.

If no global SSO session has been established, the user is redirected to the authenticator sign-on page and asked to provide a username and the appropriate credentials for that user (for example, password or certificate).

The authenticator receives the username and credentials and verifies them against the user credential store.

If verification succeeds, the authenticator establishes a global login session and directs the gatekeeper to establish a login session for the user in that Web application.

The authenticator communicates with the gatekeepers by sharing cookies or by redirecting the client browser with tokens in the query string or some other method.

Implementation strategy
Of course, the gatekeeper implementation must be consistent with the container version in which it runs. Because the filter is only supported in Servlet 2.3, earlier versions must use the Java Pet Store 1.1.2’s servlet-based architecture. To support these applications, we will write a gatekeeper based on javax.servlet.http.HttpServlet. This servlet is deployed as the gatekeeper for each legacy Java application that wishes to participate in SSO. As described in Java Pet Store 1.3, we will write a gatekeeper based on javax.servlet.Filter to support newer containers that comply with the Servlet 2.3 specification.

We must remove pre-existing calls to application-specific sign-on code. We don’t need to recode applications that use the standard interface (e.g., getUserPrincipal()) in containers that support filtering. However, we do need to recode applications that do not use the standard interface.

You can implement the authenticator in various ways. We will implement it as a Java Web application. For organizations with only Java Web applications, this approach will suffice.

However, you could extend this approach—by adding Web services to the authenticator, for example. This extension would allow non-Java applications to access the authenticator. It would also allow the authenticator to serve as a proxy for other authenticators using Security Assertion Markup Language (SAML) running under the Simple Object Access Protocol (SOAP). In this way, we could achieve the federation of user identities. (We could also support communication with both Microsoft’s .Net and Sun Microsystems’ Liberty Alliance servers outside the enterprise.)

To implement the credential store, we have several options. We can use an LDAP server if available, in which case the authenticator queries the LDAP server and the LDAP server queries the credential store. If an LDAP server is not available, the authenticator can query a relational database directly.
http://www.opengroup.org/security/sso/sso_intro.htm
Introduction to Single Sign-On
As IT systems proliferate to support business processes, users and system administrators are faced with an increasingly complicated interface to accomplish their job functions. Users typically have to sign-on to multiple systems, necessitating an equivalent number of sign-on dialogues, each of which may involve different usernames and authentication information. System administrators are faced with managing user accounts within each of the multiple systems to be accessed in a co-ordinated manner in order to maintain the integrity of security policy enforcement. This legacy approach to user sign-on to multiple systems is illustrated below:

Legacy Approach to User Sign-on to Multiple Systems
Historically a distributed system has been assembled from components that act as independent security domains. These components comprise individual platforms with associated operating system and applications.
These components act as independent domains in the sense that an end-user has to identify and authenticate himself independently to each of the domains with which he wishes to interact. This scenario is illustrated above. The end user interacts initially with a Primary Domain to establish a session with that primary domain. This is termed the Primary Domain Sign-On in the above diagram and requires the end user to supply a set of user credentials applicable to the primary domain, for example a username and password. The primary domain session is typically represented by an operating system session shell executed on the end user’s workstation within an environment representative of the end user (e.g., process atrributes, environment variables and home directory). From this primary domain session shell the user is able to invoke the services of the other domains, such as platforms or applications.
To invoke the services of a secondary domain an end user is required to perform a Secondary Domain Sign-on. This requires the end user to supply a further set of user credentials applicable to that secondary domain. An end user has to conduct a separate sign-on dialogue with each secondary domain that the end user requires to use. The secondary domain session is typically represented by an operating system shell or an application shell, again within an environment representative of the end user. From the management perspective the legacy approach requires independent management of each domain and the use of multiple user account management interfaces. Considerations of both usability and security give rise to a need to co-ordinate and where possible integrate user sign-on functions and user account management functions for the multitude of different domains now found within an enterprise. A service that provides such co-ordination and integration can provide real cost benefits to an enterprise through:
  • reduction in the time taken by users in sign-on operations to individual domains, including reducing the possibility of such sign-on operations failing
  • improved security through the reduced need for a user to handle and remember multiple sets of authentication information.
  • reduction in the time taken, and improved response, by system administrators in adding and removing users to the system or modifying their access rights.
  • improved security through the enhanced ability of system administrators to maintain the integrity of user account configuration including the ability to inhibit or remove an individual user’s access to all system resources in a co-ordinated and consistent manner.

Single User Sign-On To Multiple Services
Such a service has been termed Single Sign-On after the end-user perception of the impact of this service. However, both the end-user and management aspects of the service are equally important. This approach is illustrated in the diagram above. In the single sign-on approach the system is required to collect from the user as, part of the primary sign-on, all the identification and user credential information necessary to support the authentication of the user to each of the secondary domains that the user may potentially require to interact with. The information supplied by the user is then used by Single Sign-On Services within the primary domain to support the authentication of the end user to each of the secondary domains with which the user actually requests to interact.
The information supplied by the end-user as part of the Primary Domain Sign-On procedure may be used in support of secondary domain sign-on in several ways:
  • Directly, the information supplied by the user is passed to a secondary domain as part of a secondary sign-on.
  • Indirectly, the information supplied by the user is used to retrieve other user identification and user credential information stored within the a single sign-on management information base. The retrieved information is then used as the basis for a secondary domain sign-on operation.
  • Immediately, to establish a session with a secondary domain as part of the initial session establishment. This implies that application clients are automatically invoked and communications established at the time of the primary sign-on operation.
  • Temorarily stored or cached and used at the time a request for the secondary domain services is made by the end-user.
From a management perspective the single sign-on model provides a single user account management interface through which all the component domains may be managed in a coordinated and synchronised manner.
Significant security aspects of the Single Sign-On model are:
  • the secondary domains have to trust the primary domain to:
    • correctly assert the identity and authentication credentials of the end user,
    • protect the authentication credentials used to verify the end user identity to the secondary domain from unauthorised use.
  • The authentication credentials have to be protected when transfered between the primary and secondary domains against threats arising from interception or eavsdropping leading to possible masquerade attacks.


2005年09月07日

WebLogic平台的Web SSO(SAML)解决方案

时间:2005-07-04

作者:马晓强

浏览次数: 1030

本文关键字:


文章工具

推荐给朋友 推荐给朋友

打印文章 打印文章

SSO(Single Sign-On)即所谓的单点登录。用户在一处登录后访问其他网站时不需要再次输入用户名和口令,即可完成身份验证。

  文章《体验WebLogic Server 8.1 SP4新增功能之WebLogic Single Sign-On》(http://dev2dev.bea.com.cn/techdoc/200507499.html) 中介绍了使用WLS8.1 SP4版本中的Single Pass Negotiate Identity Assertion Provider完成与Windows平台的SSO。但有更多的人可能希望在不借助,或者不与Windows集成的情况下完成Single Sign-On。Kerberos当然可以是其中的一种解决办法,但是目前互联网上应用更多的是SAML,一个用于在网络实体间交换安全认证信息的基于 XML的框架。

  本文据此提出一种适用(针对)于WebLogic Server的,简单、可行的SSO解决方案。这个方案以集中统一的用户信息为基础,但不包括通常理解的权限管理,而仅仅提供一个身份验证的服务。因为一般情况下,一个企业内部的多个成熟系统通常分别有自己的已经比较完善的用户身份验证和权限管理功能。在这种情况下,为整合多个业务系统而提供包括权限管理在内的多种安全服务,常常将问题复杂化(尽管SAML可以做到这一点)。

  因此本文提出的方案将只解决用户的身份验证,即实现SSO的本义。在SSO帮助用户完成身份验证后,由各个业务系统本身的权限管理进行用户行为的进一步控制。这样不仅完成了用户帐号的集中管理(SAML可以完成不同系统间不同帐号的federated但不在本文讨论范围内),又不失原有系统灵活的权限控制。而且方案简单可行,不需要对原有应用做较大更改,适合快速解决Single Sign-On问题。

  如果有更复杂的需求,完全可以在本文的基础上,参考Shibboleth(http://shibboleth.internet2.edu/)项目以及SourceID(http://www.sourceid.org/index.html)的项目进行深入的研究和了解,以找出最适合自己的解决方案。

名词

SAML

  本文将以SAML 1.1实现SSO。SAML定义了一个用于在线商业系统间交换安全信息的基于XML的框架,它由OASIS (the Organization for the Advancement of Structured Information Standards)组织的Security Services Technical Committee (SSTC)开发。详情参考文章后面的参考资料部分。

OpenSAML

  一个开源的SAML1.1实现,本文使用opensaml1.1完成与SAML相关的逻辑处理。OpenSAML是Shibboleth项目的一部分。Shibboleth是一个针对SSO的开源项目。

WebLogic Server

  业界领先的J2EE应用服务器。本文的方案以WebLogic Server 8.1SP4为基础。本文附带的Demo应用只能跑在WLS8.1 SP4上,如果8.1SP3等版本需要适当改动。

Identity Assertion Provider

  Identity Assertion Provider是WebLogic 7以后提供的众多Provider的一种,它其实就是一个Authentication Provider,只不过它不需要口令来完成用户的身份验证;如果在其他平台比如Tomcat上实现,也可以是一个普通的LoginModule,只需要通过CallbackHandler获取Token然后验证就可以了。

  本文附带一个示例的Identity Assertion Provider。

Java KeyStore

  本文将附带一个自签名的java key store,它由JDK带的Keytool生成并签名。

Service Provide

  服务提供者。就是我们一般理解的业务系统,它通过配置在其上的Identity Assertion Provider完成对用户提交Token的校验,一般又称为SAML Assertion Consumer。文章后面简称为SP。

Identity Provider

  身份认证提供者。通过它对用户进行身份验证,以及生成SAML Assertion Token,又称为SAML Assertion Productor。本方案的实现中核心为一个Servlet。文章后面简称为IDP。

Use Case

  本文描述的方案实现了SAML 1.1 提供的POST Profile User Case,并有适当修改。

*

用户打开浏览器访问Service Provider 网站,访问受SAML Auth Filter保护的页面
*

SP网站的SAML Auth Filter 检查到用户没有登录,那么将用户请求的页面地址(TARGET)附加在IDP的URI之后,并将用户的浏览器重定向到IDP网站
*

否则SP网站接受用户请求

*

IDP网站接受到用户请求,判断用户是否已经登录
*

如果用户已经在IDP登录,那么到10
*

如果用户没有在IDP登录,那么向用户响应登录表单
*

用户通过IDP传回的登录表单,输入用户名和口令并提交登录请求
*

IDP接受到用户登录请求,使用用户提交的用户名和口令进行身份验证
*

如果验证失败,向用户响应登录失败页面

*

如果登录成功,并且提交的Query String中指定了TARGET,那么会向用户响应一个自动提交表单,将SAML Assertion Token提交到TARGET指定的URL

*

SP网站接受到用户提交的SAML Assertion Token,并将Token传递给Identity Assertion Provider
*

Identity Assertion Provider校验Token是否合法,并从中读取用户信息
*

如果Token通过验证,Identity Assertion Provider返回经过验证的Subject,否则抛出验证异常
*

SP获取到Identity Assertion Provider返回的Subject,表示用户登录成功,返回用户请求的页面
*

否则SP获取到Identity Assertion Provider抛出的LoginException,向用户响应登录失败页面,用户登录失败

技术实现

  这里描述一下前面Use Case中涉及的几个技术方面。

*

从安全角度考虑,用户到IDP和SP间的连接必须通过HTTPS,尤其是在外网Internet;对于内部网络Intranet应用可以通过其他办法强化网络安全

*

使用SAML Auth Filter控制哪些页面加入SSO

<filter-mapping>

<filter-name>SAMLAuthFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

  这里表示SP全部的页面受SAMLAuthFilter保护。

*

IDP根据用户提交的帐号和口令进行身份验证

  我们使用 WebLogic提供的 API进行用户身份验证,这样才能完成一个让 WebLogic Server认为是合法的登录。这个weblogic.servlet.security.ServletAuthentication提供的方法具体实现在不同的SP版本中总有变化,比如WLS8.1 SP3和8.1 SP4,因此需要留意这一点。本文方案的实现,以WELS8.1SP4为准。

public static int login(java.lang.String username,

java.lang.String password,

javax.servlet.http.HttpServletRequest request)

throws javax.security.auth.login.LoginException

Returns an int value for AUTHENTICATED or FAILED_AUTHENTICATION after using the username and password to authenticate the user and setting that user information into the session. This method is similar to "weak", except that the LoginException is propogated to caller.

Parameters:

username – String

password – String

request – HttpServletRequest

Returns:

int authentication value

Throws:

javax.security.auth.login.LoginException -

*

IDP根据用户信息生成相应的SAML Assertion Token

这里的代码来自于opensaml提供的POSTProfileTest.java,用于生成 SAMLResponse并进行签名

SAMLResponse r = SAMLPOSTProfile.prepare(

"www.opensaml.org",

"www.opensaml.org",

Collections.singleton("http://www.opensaml.org"),

"foo",

"foo",

null,

"127.0.0.1",

"foo",

new Date(),

Collections.singleton(

new SAMLAuthorityBinding(SAMLBinding.SAML_SOAP_HTTPS,

"http://www.opensaml.org",

new QName(XML.SAMLP_NS,"AttributeQuery")

)

)

);

assertNotNull("No SAMLResponse was generated.",r);

Iterator i = r.getAssertions();

((SAMLAssertion)i.next()).sign(

XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,

ks.getKey(alias,password),

Arrays.asList(ks.getCertificateChain(alias))

);

r.sign(

XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,

ks.getKey(alias,password),

Arrays.asList(ks.getCertificateChain(alias))

);

*

Identity Assertion Provider校验IDP生成的Token

  具体Identity Assertion Provider的实现超出了本文讨论的篇幅。这里只描述其需要实现的主要逻辑,同样来自于POSTProfileTest.java

assertTrue("SAMLResponse is not signed.",r.isSigned());

System.err.println("================ Generated Response ===============");

r.toStream(System.err);

System.err.println();

r.verify(ks.getCertificate(alias));

SAMLResponse r2 = SAMLPOSTProfile.accept(r.toBase64(), "www.opensaml.org", 60, true);

assertTrue("SAMLResponse is not signed.",r2.isSigned());

SAMLPOSTProfile.getSSOAssertion(r2,Collections.singleton("http://www.opensaml.org")).verify(ks.getCertificate(alias));

r2.verify(ks.getCertificate(alias));

System.err.println("================ Verified Response ===============");

r2.toStream(System.err);

System.err.println();



  只要将上面的逻辑放入在Identity Assertion Provider中就可以了。

*

自动提交表单

  在IDP响应给用户的页面包含了一个自动提交的表单,将SAML Assertion Token通过HTTP POST提交给用户请求的SP页面。这部分由SAML1.1中的Browser/POST Profile定义。由于生成的SAML Assertion往往比较大,不能通过HTTP GET提交,因此通过自动提交表单完成。这样用户仍然可能会感受到短暂的跳转,如果使用Browser/Artifact Profile,那么将由SP和IDP进行沟通,用户感受会好一点,但是开发,部署均麻烦一些,SP和IDP需要双向SSL,并且opensaml没有提供这个实现,这里就不深入讨论了。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<html>

<head>

<title>Auto Submit</title>

</head>

<body onLoad="document.myform.submit()">

<form name="myform" action="">

</form>

</body>

</html>

  综上,大家看是不是很简单呢?J

Demo的部署和演示

  这里介绍附带的几个文件

sp.war

  Service Provider应用,可以直接部署在WebLogic Server上。

idp.war

  Identity Provider应用。可以直接部署在WebLogic Server上。其中主要就是一个LogonServlet

samlIdentityProvider.jar

  这里提供的SAML Identity Assertion Provider只是为了演示使用,如果需要应用在具体的生产环境中,则需要详尽的测试,调优,以及适当的修改。

opensaml.jar

  运行OpenSAML需要的jar包,同时它使用了很多第三方的类库,因此这些第三方的jar包也需要,由于文件太大,不在附件中,大家可以去www.opensaml.org下载最新版本。

xbean.jar

  包含在WLS8 /server/lib目录下,需要在启动WLS的脚本中加入到classpath中

endorsed

  OpenSAML要求使用的XML Parser,在附件中

idp.jks

  使用keytool生成的KeyStore,存放了一对密钥

idp.cer

  密钥对中的公钥,SP使用它校验Token是否有效

  下面介绍Demo的部署过程。

*

解开附件的压缩包,将opensaml.jar以及其使用到的第三方jar包和xbean.jar放在适当地方;将endorsed目录放在适当地方,将在2步骤中使用
*

修改启动WebLogic的脚本,在CLASSPATH中增加指向opensaml.jar以及其第三方jar和xbean.jar(WebLogic8中也带有该jar)的路径,并设置系统变量-Djava.endorsed.dirs=<endorsed目录>
*

为验证SSO需要将sp.war和idp.war分别部署在两台WebLogic Server上。修改idp.war/WEB-INF/web.xml中在path参数中指明idp.jks的文件路径,以及访问keystore的口令 123456(这里keystore口令和alias的主口令设置为一致,否则此处需要多设置一个配置项);修改sp.war/WEB- INF/web.xml,在redirectURL参数配置IDP网站的地址,指向SAMLLogon 这个Servlet在IDP上映射的URL。
*

在SP上配置SAML Identity Assertion Provider(IDP所在的WLS不需要配置)
o

将samlSecurityProvider.jar 拷贝至 /server/lib/mbeantypes下。如果有Managed Server并且Managed Server在另外一台物理机器上或另外一个独立的WL安装目录下,那么同样需要将samlSecurityProvider.jar拷贝至对应的 mbeantypes目录下
o

重新启动全部的Server
o

通过WebLogic Console配置SAML Identity Assertion Provider,在Detail中指明idp.cer证书的路径,别名,以及口令。需要注意一点就是,需要将Base64的选择取消
o

重新启动全部的WebLogic Server
*

在SP 和IDP两个系统的WebLogic Server Realm中增加一个测试用户,为sso_user并设置口令,如果SP和IDP部署在同一个WLS Domain,那在WLS Admin Console上做一次就可以了;如果有统一的用户存储,那么部署对应的Authentication Provider就可以了

  至此,部署成功。

下面是演示过程:

演示一:

*

访问SP网站的受保护页面http://localhost:19001/sp/index.jsp
*

浏览器被重定向到IDP网站被要求登录

*

输入用户sso_user以及用户口令登录
*

登录成功后浏览器返回 http://localhost:19001/sp/index.jsp页面内容

演示二:

*

访问IDP网站的登录页面 http://localhost:18000/logon
*

在登录表单中输入用户名sso_user和口令

*

登录成功后,显示IDP欢迎页面以及用户登录成功的帐号

*

手工在浏览器中输入地址 http://localhost:19001/sp/index.jsp
*

浏览器显示SP页面内容而不需要再登录



演示三(图片省略):

  如果IDP网站当机,那么只是丧失SSO而已,不会影响业务系统的使用,这一点对大的应用来说很重要。

*

访问SP的登录页面 http://localhost:19001/sp/logon.jsp
*

在登录表单中输入用户名sso_user和口令,进行登录
*

登录成功后,欢迎页面显示用户的帐号信息

参考资料

*

http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=securityOASIS关于SAML的站点
*

http://www.opensaml.orgOpenSAML的网站,它是一个叫Shibboleth项目的一部分。Shibboleth项目主要应用在校园内,以及校园间的应用系统的用户身份联合认证。也有不少商业和政府网站采用
*

http://www.sourceid.org/index.htmlSourceID 是非常有实力的一个开源组织,旗下有多个开源项目(SAML、Liberty Alliance,WS-Federation)。SSO是其主要目的之一,当然不仅限于此,更着重于用户身份的联合,以及安全信息的共享。比如用户在网站1的帐号是User1,在网站2的帐号是User 2,那么如何实现SSO呢?
*

http://e-docs.bea.com/wls/docs81/security/index.html更多关于开发WebLogic Security Provider的信息

示例程序

作者简介




马晓强是高级软件工程师,现在广东从事J2EE,LDAP相关的设计开发工作。对WebLogic,LDAP以及Single Sign-On等产品、技术很感兴趣。

2005年09月05日

性能比较:.NET Remoting 与 ASP.NET Web 服务


使用 Microsoft .NET 建立分布式应用程序
2002年9月

适用于:
   Microsoft® .NET Remoting
   Microsoft® ASP.NET Web 服务

摘要:本文对 Microsoft ASP.NET Web 服务与 Microsoft .NET Remoting 的相对性能进行比较。Microsoft ASP.NET Web 服务的互操作性最好,并完全支持 HTTP 上的 WSDL 和 SOAP;而 Microsoft .NET Remoting 可实现公共语言运行库类型系统的高保真,并支持其他数据格式和通信通道。

从 MSDN Code Center 下载 BDADotnet.msi 示例代码(英文)。

目录

简介

ASP.NET Web 服务和 .NET Remoting 为分布式应用程序中的进程间通信提供了一整套设计选项。通常,ASP.NET Web 服务的互操作性最好,并完全支持 HTTP 上的 WSDL 和 SOAP;而 .NET Remoting 可实现公共语言运行库类型系统的高保真,并支持其他数据格式和通信通道。有关详细信息,请参阅 ASP.NET Web 服务还是 .NET Remoting:如何选择

本文主要对这两项技术的相对性能进行比较。

ASP.NET Web 服务

ASP.NET 提供以 Microsoft® IIS 作为宿主的基础结构,支持 SOAP、XML 和 WSDL 等行业标准。尽管 .NET Remoting 也支持 IIS 宿主和 HTTP 上的 SOAP,但 ASP.NET 却可提供最高级别的 SOAP 互操作性,包括对 SOAP Section 5 和 Document/Literal 的支持。

ASP.NET 可以充分利用 IIS 具有的功能,如安全性和日志记录。IIS 宿主也很强大,因为它可以在 Aspnet_wp.exe 终止后重新生成它。此外,由于 ASP.NET Web 服务的服务器和客户端的配置都已简化,因此与使用 .NET Remoting 提供的服务相比,它的创建和使用更为容易。

有关详细信息,请参阅 .NET Framework Developer’s Guide 中的 Building XML Web Services Using ASP.NET(英文)。

.NET Remoting

.NET Remoting 更具通用性和扩展性,允许在使用不同传输协议和序列化格式的对象间进行通信。它支持二进制、SOAP、自定义格式以及 TCP、HTTP 和自定义协议。支持多对象创建和生存期模式,包括 Singleton、SingleCall 和 Client-Activated。Remoting 需要一个主机进程,可以是 IIS、Microsoft® Windows 服务或用 .NET 编写的可执行文件。

在具有 ASP.NET 的 IIS 中宿主使用 SOAP 格式化程序的 .NET Remoting 对象时,该对象可以公开为 XML Web 服务。由于有效负载以 HTTP 上的 SOAP 进行编码,因此任何支持 SOAP 编码格式的客户端均可通过 Internet 访问该对象。使用 HTTP 协议的另一个优点是它通常可以畅通无阻地通过大多数防火墙。TCP 通道和二进制格式化程序可以部署在服务器和客户端均运行 .NET Framework 的 Intranet 环境中。此方法的性能最佳,因为在使用原始套接字通过网络传输数据时使用了效率高于 HTTP 的自定义协议。尽管此方法在封闭环境中可以提供出众的性能,但它不能部署于客户端未运行 .NET Framework 的跨平台方案。

IIS 主机使用安全套接字层 (SSL) 为网络级保护提供安全通信,您也可以利用 IIS 和 ASP.NET 身份验证和授权。TCP 通道以及不通过 IIS 宿主的 HTTP 通道不支持安全套接字传输,因此其数据以明文形式传输。如果使用的是 TCP 通道或由非 IIS 进程宿主的 HTTP 通道,则您需要负责实现其安全性。

有关更多详细信息,请参阅 .NET Framework Developer’s Guide 中的 .NET Remoting Overview(英文)。

测试方案

分布式应用程序中进程间通信的性能取决于以下因素:

用于跨远程边界的应用程序间传输信息的通道(包括 TCP 和 HTTP)占用的系统开销量。TCP 套接字比 HTTP 更为有效。

另一个因素是序列化。序列化流可以通过 XML、SOAP 或压缩二进制表示法进行编码。ASP.NET Web 服务使用 XMLSerializer 类将对象序列化为 XML 流,XML 流的速度非常快,但由于存在 XML 分析,因而需要一定的系统开销。Remoting 分别使用 BinaryFormatterSOAPFormatter 将对象序列化为二进制格式和 SOAP 格式。由于这些格式化程序使用反射,因而对于引用对象很快,但对于必须经过装箱或取消装箱来通过反射 API 传递的值类型则较慢。此外,SOAPFormatter 还需要额外的系统开销以生成编码的 SOAP 消息。

本比较中使用的测试基于访问客户和订单数据的普通业务方案。为使测试尽可能符合实际,数据库中包含 100,000 多行客户帐户。数据位于 Microsoft® SQL Server™ 2000 数据库中,并使用 SQL Server .NET 数据提供程序连接到 SQL Server。

性能比较中使用了以下方法:

GetOrderStatus

GetOrderStatus 方法接受 OrderId 并返回表示订单状态的整数。

GetCustomers

GetCustomers 方法接受 CustomerId 和参数以指定想要读取的客户行数目,并读取 CustomerId 大于传递给 Web 服务方法的 CustomerId 的前 n 行。

测试过程中,我们通过具有不同页面大小(20 和 50)逐页提取小客户行集合。

测试工具和策略

测试中,ASPX Web 页调用包含测试代码的远程对象。尽管直接测试该技术(而不是通过在 Web 服务器后端测试)可以得到更好的绝对性能,但是在无状态环境中测试对于普通应用程序方案来说更符合实际。另外,有很多测试工具可以通过提供多线程测试和可靠的性能统计对 Web 页进行适当的强度测试。

在本测试中,我们使用了 Microsoft 应用程序中心测试 (ACT)。它可以对 Web 服务器进行强度测试,分析 Web 应用程序(包括 ASPX 页及其使用的组件)的性能和可伸缩性问题。有关如何创建和运行测试的详细信息,请参阅 ACT 文档。通过打开到服务器的多个连接并迅速发送 HTTP 请求,应用程序中心测试可以模拟一大组用户。它还允许我们建立实际的测试方案,我们可以在方案中使用一组随机参数值调用同一个方法。此功能很重要,因为用户不可能会使用相同的参数值反复调用同一个方法。另一个有用的功能是,应用程序中心测试可以记录测试结果,从而提供有关 Web 应用程序性能的最重要的信息。

如前所述,远程对象有两种激活方法 – 服务器激活和客户端激活。服务器直接控制服务器激活对象的生存期。服务器激活对象有两种激活模式 – SingletonSingleCall。Singleton 类型不能同时运行一个以上的实例。所有客户端请求由一个实例提供服务,因此,使用该激活模式可以维护客户端之间的状态。另一方面,对于 SingleCall 类型而言,每个客户端请求由一个不同的实例来服务。客户端激活对象在服务器上创建,但这些对象的生存期却由调用应用程序域控制。使用此模式可以维护来自同一客户端的请求间的状态。ASP.NET 仅支持 SingleCall(即每个请求由一个新实例提供服务),如果服务是有状态的,则必须使用 cookie 和 SessionState 或自定义 SOAP 标头对其进行管理。在已经执行的所有用于比较各种远程选项的测试中,使用了 SingleCall 模式进行合理比较。

尽管 ASP.NET Web 服务支持 SOAP、HTTP-GET 和 HTTP-POST 选项,但为了保持一致性,测试中仅使用了 SOAP 选项。

HTTP/1.1 建议任何单个客户端与单个服务器之间至多建立两个连接。因此,当使用 HTTP 协议进行通信(如使用 HTTP 通道和 ASP.NET)时,在默认情况下,该协议在任何给定时间只打开两个到给定服务器的连接;而 TCP 通道可根据向服务器发出请求的线程数目,打开多个连接。为了模拟多个向远程对象发送同步请求的客户端,我们使用客户端配置文件将每个客户端与服务器的连接数目由默认值 2 改为 100:

使用 HTTP 通道进行远程通信时 – 使用客户端 .config 文件中的 clientConnectionLimit 属性:

<system.runtime.remoting>
   <application>
         ...
    <channels>
      <channel ref="http" clientConnectionLimit="100">
         <clientProviders>
            <formatter ref="soap" />
         </clientProviders>
      </channel>
   </channels>
      </application>
 </system.runtime.remoting>

对于 ASP.NET Web 服务,使用客户端 .config 文件中 <system.net> 中的 maxConnection 属性:

    <system.net>
        <connectionManagement>
            <add address="*"
                 maxconnection="100"
            />
        </connectionManagement>
    </system.net>

由于允许与“localhost”(即客户端和服务器在同一计算机上)建立无限多个 HTTP 连接,因此不需要更改配置文件。

计算机配置

下表提供了用于执行测试的测试台配置的简单摘要。

表 1:客户端计算机配置

客户端数量 计算机/CPU CPU 数量 内存 硬盘 软件
1 Compaq Proliant 1130 MHz 2 1GB 16.9 GB
  • Windows 2000 Advance Server SP 2
  • 应用程序中心测试

表 2:Web 服务器配置

服务器数量 计算机/CPU CPU 数量 内存 硬盘 软件
3 Compaq Proliant 1000 MHz 2 1 GB 16.9 GB
  • Windows 2000 Advance Server SP 2
  • .NET Framework SP1 发行版本

表 3:应用程序服务器配置

服务器数量 计算机/CPU CPU 数量 内存 硬盘 软件
1 Compaq Proliant 1126 MHz 2 1 GB 16.9 GB
  • Windows 2000 Advance Server SP 2
  • .NET Framework SP1 发行版本

表 4:数据库服务器配置

服务器数量 计算机/CPU CPU 数量 内存 硬盘 软件
1 Compaq Proliant 700 MHz 4 4 GB 18 GB
  • Windows 2000 Advance Server SP 2
  • SQL Server Enterprise Edition SP 2

性能测试结果

吞吐量和滞后时间是关键的性能指标。对于给定数量的返回数据,吞吐量是指单位时间(通常是 1 秒)内处理的客户端请求数量。因为从可用性角度来看,吞吐量在某一响应时间达到峰值是不能接受的,因此我们跟踪了滞后时间,利用由应用程序中心测试为每个运行的测试生成的报告,将其作为响应时间进行测定。

跨计算机方案

在跨计算机方案中,远程客户端和远程对象位于不同的计算机中。ACT 客户端向 ASPX Web 页发送请求,该页随后调用远程对象中的方法。

图 1:跨计算机方案

如图 1 所示,测试是在 Web 服务器后端执行的,并存在数据库访问以及到外部计算机的网络跃点,从而增加了额外的系统开销。因此,生成的吞吐量和滞后时间性能值仅作为比较这两项技术的基础,它们不代表绝对性能。使用 ASP.NET Web 服务和 .NET Remoting 构建的分布式系统的精确吞吐量和滞后时间取决于所使用的体系结构。

GetOrderStatus

当从数据库中获得单个值后,我们将对各种技术的表现进行比较。

图 2:GetOrderStatus:吞吐量和滞后时间

注意:

  • ASMX:ASP.NET Web 服务
  • 所有其他选项表示不同的 .NET Remoting 配置。
  • 在所有其他选项中,名称隐含了主机、使用的传输协议和格式,即 Host_TransaportProtocol_Format。
  • “WS”即 Windows Service(Windows 服务)的缩写,它托管了远程类型。
  • IIS_HTTP_Binary/SOAP 托管于带有 ASP.NET 的 IIS 中。

如图 2 所示(该对象配置为使用 TCP 通道和二进制格式化程序,主机是 Windows 服务),WS_TCP_Binary 比其他分布式技术的性能要好。这是因为该方法通过原始 TCP 套接字传输二进制数据(比 HTTP 的效率高),且数据不需要编码/解码,因而降低了系统开销。可以看到,WS_TCP_Binary 和最慢的方法之间存在约 60% 的性能差距。

尽管 IIS_HTTP_Binary 与 WS_HTTP_Binary 产生的二进制有效负载相同,但它的速度较慢,原因是存在着从 IIS (Inetinfo.exe) 向 Aspnet_wp.exe 的额外进程跃点。IIS_HTTP_SOAP 和 WS_HTTP_SOAP 之间的性能差别也由此造成。

WS_HTTP_Binary 和 WS_TCP_SOAP 的性能几乎相同。尽管前者有 HTTP 分析方面的额外系统开销,后者有 SOAP 分析方面的额外系统开销,但在本例中 HTTP 分析的系统开销与 SOAP 分析的系统开销几乎相同。

ASP.NET Web 服务的性能优于 IIS_HTTP_SOAP 和 WS_HTTP_SOAP,因为 ASP.NET XML 序列化比 .NET Remoting SOAP 序列化的效率高。从图 2 可以看出,ASP.NET Web 服务与 IIS_HTTP_Binary 的性能几乎相同。

使用自定义类的 GetCustomers

本节中,远程方法从数据库中检索客户记录,并将其放到 DataReader 中,然后使用 DataReader 中的数据导入一个 Customers 对象,并返回 Customers 对象。我们用 20 行和 50 行的结果集合来进行测试,以了解返回数据的数量对性能的影响。

图 3:GetCustomers(n=20):吞吐量和滞后时间

其他选项的相对性能远远超过了 WS_TCP_Binary,因为此时 Customers 对象的封送处理成本成了重要的影响因素。本测试中,我们对一个包含 20 个客户的 Customers 对象进行序列化,而前一个测试是对整数进行了序列化。

IIS_HTTP_Binary 比 WS_HTTP_Binary 略慢,这是因为存在前面例子中所提到的额外进程跃点。请注意,ASP.NET Web 服务的性能与 IIS_HTTP_Binary 的性能非常相似。

随着数据不断增多,WS_TCP_SOAP 的性能明显下降,现在与 WS_HTTP_SOAP 和 IIS_HTTP_SOAP 相当。原因是此时大部分时间都用于序列化数据上,它成为影响性能的主要因素。

图 4:GetCustomers(n=50):吞吐量和滞后时间

注意:

  • ASMX_SOAPExtn:使用 SOAPExtension 解决 ASP.NET 的缓冲问题。

从图 4 可见,随着数据量的增大,WS_TCP_Binary 和其他选项之间的性能差异进一步缩小。

请注意,ASP.NET Web 服务已落后于 IIS_HTTP_Binary。原因是 ASP.NET 中存在大量的缓冲信息,该问题将在下个版本中得到更正。缓冲问题解决后,ASMX 选项将与 IIS_HTTP_Binary 一致(正如前面测试中所看到的)。

使用 SOAPExtension 可解决缓冲问题,这是因为它可以在 XmlSerializer 和网络间提供一些缓冲。如图所示,ASMX_SOAPExtn 选项(使用已实现的 SOAPExtension)显著改进了 ASMX 选项的性能,并仅次于 IIS_HTTP_Binary。SOAPExtension 包含在用可下载的 .NET 示例代码构建分布式应用程序中。

WS_TCP_SOAP、WS_HTTP_SOAP 和 IIS_HTTP_SOAP 性能相近,其中 WS_TCP_SOAP 稍快一些。

使用 DataSet 的 GetCustomers

在下一组测试中,远程方法从 DataSet 中的数据库检索客户记录,并返回到客户端。

图 5:GetCustomers(n=20):吞吐量和滞后时间

由于此处数据集封送处理需要的系统开销成为重要因素,WS_TCP_Binary 和其他方法之间的性能差别已逐渐减小。

IIS_HTTP_Binary 略快于 WS_HTTP_Binary。与数据封送处理成本相比,后者的额外进程跃点成本可以忽略不计。

请注意,ASP.NET Web 服务的性能已下降很多,以致与 WS_TCP_SOAP、WS_HTTP_SOAP 和 IIS_HTTP_SOAP 的性能相近。此性能下降主要归因于两个已知的 ASP.NET 问题,这些问题将在下一版本中更正。一个是前面讨论过的缓冲问题,另一个则与 ASP.NET 中的 DataSet 序列化有关。这些问题解决后,ASP.NET Web 服务就接近 IIS_HTTP_Binary 了。通过解决大量信息的缓冲问题,ASMX_SOAPExtn 显著改进了 ASMX(如图 5 所示),但由于 DataSet 序列化问题的存在,性能仍有所降低。

图 6:GetCustomers(n=50):吞吐量和滞后时间

由于该数据集比上一个测试中的数据集大,WS_TCP_Binary 与其他方法之间的性能差异明显缩小。可以看到,WS_HTTP_SOAP 和 IIS_HTTP_SOAP 的性能非常接近。

由于存在前面讨论过的已知问题,ASP.NET Web 服务方法越发落后。请注意,仅仅解决了缓冲问题,ASMX_SOAPExtn 就显著改进了 ASMX。

小结

正如以上测试所示,ASP.NET Web 服务和 .NET Remoting 的各种设计选项花费的系统开销差别很大,因此性能差别很明显。传递数据的大小也是一个重要的影响因素,可以使其他设计选项之间的差别成倍增加。本次比较只包括无状态的同步远程过程调用,不包括影响分布式应用程序性能的其他重要性能因素,如身份验证、授权及数据保密等。

尽管 .NET Remoting 基础结构和 ASP.NET Web 服务均可实现进程间通信,但它们的专业程度和灵活性各具特色,可以满足不同层次的目标用户。如果您的应用程序需要与其他平台或操作系统进行互操作,最好使用 ASP.NET Web 服务,因为它们支持 SOAP Section 5 和 Document/Literal,因而灵活性更好。另一方面,当您需要更丰富的面向对象的编程模型时,请使用 .NET Remoting。有关详细信息,请参阅 ASP.NET Web 服务还是 .NET Remoting:如何选择。在性能是主要要求而不太关心安全性和进程生命周期的方案中,可以选择 .NET Remoting TCP/二进制;但是请记住,当使用 IIS 主机实现时,可以通过向系统中添加更多的计算机来改善性能,而 .NET Remoting TCP/二进制实现则不能。

2005年08月15日

先决条件:
1、开发工具Eclipse安装了插件Lomboz,并指明Server为JBoss
2、已经在Jboss中建立了与MySql的DataSource连接,JNDI为 java:/MySqlDS
3、已经在MySql中建立了表 CAT
Column | Type | Modifiers
——–+———————–+———–
cat_id | character(32) | not null
name | character varying(16) | not null
sex | character(1) |
weight | real |
Indexes: cat_pkey primary key btree (cat_id)

整合步骤:
1、生成一个WEB应用
2、在这个应用的WEB-INF\lib下应该包含以下Hibernate必需包
hibernate2.jar
odmg-3.0.jar
commons-collections-2.1.1.jar
commons-logging-1.0.4.jar
dom4j-1.4.jar
ehcache-0.9.jar
cglib-full-2.0.2.jar
3、在这个应用的WEB-INF\classes下生成Hibernate配置文件hibernate.cfg.xml(也可以用hibernate.properties,此处不议),内容如下:
<?xml version=’1.0′ encoding=’utf-8′?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory name="hibernate/SessionFactory">
<property name="connection.datasource">java:/MySqlDS</property>
<property name="show_sql">true</property>
<property name="dialect">hibernate.dialect net.sf.hibernate.dialect.MySQLDialect</property>

<!– Mapping files –>
<mapping resource="Cat.hbm.xml"/>
</session-factory>
</hibernate-configuration>

hibernate/SessionFactory为你需要绑定SessionFactory的JNDI名(绑定之后可以在容器内用Context lookup)。
java:/MySqlDS为你已经绑定好的MySql DataSource名。
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect为Hibernate指明数据库方言为MYSQL。
Cat.hbm.xml为Hibernate映射文件,下面会提到。

4、定义可持久化类(POJO)– Cat.java
public class Cat {
private String id;
private String name;
private char sex;
private float weight;
public Cat() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public float getWeight() {
return weight;
}
public void setWeight(float weight) {
this.weight = weight;
}
}

5、定义类映射文件– Cat.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>

<class name="com.pbmaster.study.hibernate.po.Cat" table="CAT">

<!– A 32 hex character is our surrogate key. It’s automatically
generated by Hibernate with the UUID pattern. –>
<id name="id" type="string" unsaved-value="null" >
<column name="CAT_ID" sql-type="char(32)" not-null="true"/>
<generator class="uuid.hex"/>
</id>

<!– A cat has to have a name, but it shouldn’ be too long. –>
<property name="name">
<column name="NAME" sql-type="varchar(16)" not-null="true"/>
</property>

<property name="sex"/>

<property name="weight"/>

</class>

</hibernate-mapping>

此xml文件放置到hibernate.cfg.xml相同的目录(不知道放到其他地方行不行,待查)。

6、定义一个startup Servlet -InitHibernate.java,在Servlet的init()中启动Hibernate,并绑定JNDI
public class InitHibernate extends HttpServlet {

public void init(ServletConfig config) throws ServletException {
super.init(config);
try{
SessionFactory sf = new Configuration().configure().buildSessionFactory();
System.out.println("Hibernate Startup completed successfully");
}
catch(Exception ex){
ex.printStackTrace();
}
//TODO Method stub generated by Lomboz
}

public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
//TODO Method stub generated by Lomboz
}
}

为了能让这个Servlet能在服务器启动时被运行,需要配置WEB.XML文件:
<servlet>
<servlet-name>inithibernate</servlet-name>
<display-name>inithibernate</display-name>
<servlet-class>com.pbmaster.study.hibernate.servlet.InitHibernate</servlet-class>
<load-on-startup>10</load-on-startup>
</servle

2005年08月14日

第1招 认清人生的意义以及毕生所全力以赴的目标

  为什么要这么拼命?因为你必须对得起自己的良知。

  想要成为一个人际关系高手,第一步就必须先确认你的价值观;若是你连这个都摸不清楚,就很难去看透人生的意义,更不用说什么成就感了。


  第2招 列举出截至目前为止的五件重大成就

  知彼者,智也;知己者,大智也。

  第3招 明白自己有哪些专长和资源正是他人所迫切需要

  天生我才必有用。

  无论你的专长是得自专业训练或是业余摸索,都可转化成一股强劲的“人际关系动能”,千万不要妄自菲薄。

  第4招 挥别独行侠的日子

  还想像小学生那样科科争第一?别傻了,这个世界只有团队成绩,没有个人成绩,因此也没有所谓的“第一名”。

  告别独行侠的生涯,你的人生将从黑白转为彩色,全新出发。

  第5招 为自己建立自信,自助助人

  人人都有改造世界的能力,你自然也不例外。

  多参加一些活动,帮助别人,也是帮助自己。

  第6招 拟定短期与长期奋斗目标,定期予以审视与修改

  工作计划簿有用吗?有,至少可以让一个人培养出三分钟的热度。

  拟定目标不仅可以督促自己,也能让别人得知你有哪些需要。只要你勤于跟别人沟通,那你的朋友自然就知道你有什么困难,进而藉着人际关系这张大网来帮你早日实现自己的梦。

  第7招 绘出一张人际关系“网络图”,显现出自己在这项资源上的多样化与触角纵深

  人际关系网的特色是:每个成员都是老大。

  如果你能保有最新版本的人际关系图,就不难得知在眼前这一刻该如何以自己为主角,来善用你的人际关系资源。

  第8招 以一种相当专业化的方式来做自我介绍

  在很多场合下,你所表现出的外在形象要远比你真正的本事来得重要。

  第9招 以简洁得体又别出心裁的方式来做自我介绍

  无论是在何种社交场合,想扩展人际关系的第一课就是要学会自我介绍。

  要设法出奇制胜。让对方牢牢地记得你,而且是记得正面的形象。

  第10招 技巧性地打开话匣子

  为什么我们经常错过了许多广结人缘的机会?就是因为我们常把那些黄金时段用来绞尽脑汁,却还是挤不出一句合适的开场白。

  无论是主动或被动去打开话匣子都能得心应手。一旦你能达到这个境界,那无论把你丢在任何一个场合中,必都能迅速进入状况,随心所欲地去扩展人缘,为自己在生活与事业中,营造一个又一个绝佳的发展机会。

  第11招 有必要时,就主动再做一次自我介绍

  如果有人主动走过来跟你打招呼,那这一定是个大人物。

  多练习一下“纡尊降贵”,经常不厌其烦地做自我介绍,你的人际关系通道将会愈走愈宽,也愈走愈顺。

  第12招 看清他们的面目,牢记他们的大名

  人们其实不在乎你对他们的底细了解多少,但很在乎你有没有仔细在听。

  第13招 善于在社交场合做称职的主人

  只要地球上还有人类,就不愁没有机会去表达你的善意。

  第14招 乐于站出来为自己打知名度

  想为自己打知名度并不需要不择手段;相反地,这有助于早日实现你的理念。

  适度地推荐自己,才能让人得知在什么时候能够向你求助或请教,不致让你英雄无用武之地。

  第15招无论与任何一个人打交道,总是待之以礼

  即使人生苦短,用来学礼数也是绰绰有余了。

  想出奇制胜,翻身做主人,不必舍近求远,先把你的台词练好再说吧。

  第16招 名片必须是经过精心设计的作品

  名片的功用是要让别人能想起世上还有你这号人物。

  当别人想动用人际关系去搬救兵时,你这张名片就是一份很重要的线索,因此在设计上千万不要草率。

  第17招 随时随地携带数量充足的名片

  要上阵前,先检查自己是否已“全副武装”。

  第18招 在情况适宜时,才递上名片

  当你确信和对方有话可说之后,时机成熟时就应恭谨地奉上名片,相互约定日后联系与合作的方式,在这种稳固基础上所建立起的人际关系才能经得起考验。

  第19招 在每张所收到的名片上记载日期以及相关事项,以便于日后整理与查核

  当别人还不知道你在不在乎他们的时候,自然就不可能去在乎你。

  第20招 不要吝于表达感激之意

  成功人士有个特性,就是常怀感恩之心。

  以感恩的心来对待所有曾扶持过你的朋友们,主动表达你的由衷感激之意,慢慢地,你会发现不但自己的人际关系愈加牢固,别人也将以你为仿效的对象。

  第21招 无论认识或不认识,只要是能给予你激励或启发,就应诚挚地向他们言谢

  要以称赞来取代嫉妒之心,确实需要很大的勇气。

  当你因为提出一项绝妙点子而获得他人嘉奖时,内心是什么滋味,将心比心,无论是认识或不认识的朋友,只要是能提供净言或是言行足资借镜者,都不要忘了面露微笑地跟他们说声谢谢。把这养成习惯后,不仅是你的事业前途,连你的人生观都将改写了。

  第22招 适时以打电话、送小卡片,以及送小礼物的方式来向对方表达感激之意

  只要肯开口赞美别人,你将会是最大的赢家。

  要灌溉一株树木需要充足的阳光、水分与养分,而栽培你这棵人际关系长青树则有赖你持续性的关怀,借着打电话与送卡片、礼物等小环节来呵护这株树。可千万别让它因为营养不良而枯死。

  第23招 要有自己专用的信、卡片与便条纸

  用手写的信函比较有亲切感,给人的感受也不一样。

  想建立自己的金字招牌吗?想树立良好的专业形象吗?做点小投资吧,去印一些专用的各式文具纸,当你要寄发给客户、同行或朋友时,会觉得更体面。

  第24招 欣然接受他人的道谢与援助

  从一个人是否愿意接受他人的道谢,就可窥见其在人际关系上的功力。

  第25招 建立起一套有系统又管用的人际关系网

  将能更有效地提高你在人际关系上的运作效率。

  为什么有人是事半功倍,有人却是事倍功半?就是因为做起事来有无章法。

  第26招 名片上绝无过时的资料

  假使你没有时间去每天记载新资料,至少每周要登录一次,这样才能确保资料的正确性与完整性。

  第27招 设立一套有效的时间管理系统

  岁月不饶人。我们不能要求时间暂缓来配合我们的脚步,只能尽量迎头赶上……如果你能控制时间,你就能控制一切。

  提醒你一点,只要你肯尊重自己所制定的工作表,别人就不敢随便抓你去出公差。一旦时间资源能完全掌握在你的手里,那治国平天下都绰绰有余了。

  第28招 每天都详细检视当天的工作进度表

  要如何得知你是离成功之路愈来愈近,还是在原地打转?……最好的方法就是每天都“结帐”一次,看看工作进度表的落实程度究竟如何。

  每天结帐一次,你的心理负担就不会这么重,哪怕这是一项工程浩大的计划,你也可以感受到稳健的前进脚步。

  第29招 今日事今日毕

  其实时间没什么好管理的,因为每天都是24小时,你该担心的是要如何去摆平争食这块大饼的千百项计划。

  绝对不要效法慢郎中那样去“以债养债”,否则到最后你加班到三更半夜也还不清。不要滥用你的记事本,可以当场解决的就不要拖,无形之中,你的工作效率自然就会升高。

  第30招 必须在24小时回复所有的来电

  如果你的经营哲学是“能拖到明天,就不必急着今天做”,那你这一辈子恐怕是很难熬出头了。

  把24小时内回复所有来电养成一种习惯,就能确保你那条人际关系网络上的资讯畅通程度。

  第31招 在拿起话筒之前,先思索一下待会儿要讲些什么

  通往成功之路有四道阶梯:慎谋行动、有备而来、勇往直前和贯彻始终。

  第32招 拒绝无谓的交际应酬

  如果你现在糟蹋时间,将来时间就来糟蹋你。

  第33招 在参加社交活动之前,应妥为规划

  只要事事都能有备而来,即使祖宗没有积德,照样能飞黄腾达。

  第34招 主动寻求他人的支援

  你所处的是个万物共存的和谐社会,因此单打独斗是行不通的。

  大多数人都是乐于助人的,因此只要你认定他们不至于帮倒忙,就给他们一次表现的机会吧。

  第35招 在开口时,应简单明了地陈述要求,而且不宜展现出一副咄咄逼人的姿态

  人际关系网是怎么牵起来的?很简单,当一个愿打。另一个愿挨的时候,这段姻缘就形成了。

  第36招 只要逮到机会,就不忘冒出这句:“对了,你所认识的人当中,有哪个人……”

  你们祈求,就给你们。

  下次当你碰壁时,不妨检讨一下自己的说话技巧是否有改进的余地。其实大多数人们都是乐于助人的,不要轻率地关闭那扇机会之门。

  第37招 对于别人所提出的建议,应当即知即行

  否则等三分钟的热度过后,一切都将回到原点。光说不练,无济于事。

  第38招 每次和朋友交谈后,都能有受益非浅之感

  懂得顺水推舟的人,想不出头恐怕也难。

  第39招 积极参与各种民间社团

  借着融入这个大家庭中,你不仅造就了自己的事业,也成全了许多同伴的美梦,功德无量。

  当一群人本着相同目的而物以类聚时,人际关系就萌芽了。

  第40招 设法在社团内担任有实权的职位

  一旦你被提升为干部,就象征着你是个德高望重的前辈,而不是一个只想过来瓜分资源的庸碌之辈。

  第41招 勤于利用人际关系网来处理别人的请托事务

  圈子内最为人称颂的就是,个个都是赢家,因为胜利的果实是属于每个人的。

  如果你希望自己在落魄时能有朋友为你伸出援手,最好的因应之道就是平时多做些投资。

  第42招 举头三尺有神明,抬头三尺有人际

  要怎么培养自信?很简单,专挑那些你不在行的事情下手……只要能突破一己的心防,大胆出击,再苦撑一下,那你必然会有倒吃甘蔗之感,渐入佳境。

  第43招 经常评估你的人际关系网,不断予以扩展

  人际关系网的建立需持之以恒,而不是可以一劳永逸之事。

  第44招 相信你的直觉

  聆听你心灵的呐喊声,就能得到所有的答案。

  除非你自认已经麻木不仁了,否则没有理由忽视来自心灵深处的这股声音;让它去带领你,你就能尽早掌握状况,了解周遭的一切风吹草动。

  第45招 对于在人际关系网上的每个盟友,都会倾全力助他们步步高升

  人际关系网的维系需要诚意与耐心。

  应该借着提携盟友来培植你的实力,在这种稳固的基础上盖大楼,届时要缔造一种“双赢”的局面,也只是迟早的问题而已。

  第46招 提供朋友们一流的服务

  即使你不是投身于服务业,照样有许多服务他人的机会。

  你必须先竖立自己的金字招牌,让人际关系圈内的人都知道你这个人很可靠,这么一来,他们会很乐意做这种投资,因为他们知道你将来会回馈得更多。

  第47招 喜欢聆听朋友的心声

  有正常的听力,并不代表知道要怎么去听。

  聆听的艺术就是:耐心听别人讲话,而且不要听错!

  第48招 要有高尚节操与专业涵养

  口不择言,后患无穷。

  人际关系的确很好用,但千万不要滥用。只要待人处事都能表现出一股高尚节操与专业涵养,那即使是你的死对头也会对你心服口服,推崇备至。

  第49招 以敞开的胸襟去面对每个“结缘”的机会

  伟人与凡人的差别,在于前者能敬重每一个人,包括三餐不济的流浪汉。

  第50招 布下滴水不漏的庞大“情报网”

  能造就他人功名的仁者,必然会永垂青史。

  当你变成了叮当响的人物后,这意味着你有更多的资源去邀他人前来分享,如此“良性循环”下去。这不是很好吗!

  第51招 利用人际关系网去造就自己,嘉惠别人,成就事业,改变人生

  如果你的公私两种生活领域之间,需要一座桥梁来互通有无,那就是你的人际关系网。

  第52招 时时刻刻都以人际关系网为念

  宝剑不用就会生锈变钝,倘若每个人都能将人际关系的运用当成生活习惯,那这个世界的面貌就会完全改观。

  第53招 矢志成为强势人际关系的模范生

  一个人际关系高手绝不会以屯积资源为能事,反而是不时地主动邀他人分享,并鼓励他们也如法炮制。

  第54招 用一片人际关系网来将世界一网打尽

  这个世界的人际关系网多得惊人,几乎每个人之间都有一条脐带相连接。

  第55招 将人际关系融为生活中所不可或缺的一部分

  你所处的是个万物共存的和谐社会,因此单打独斗是行不通的

进入vi的命令
vi filename :打开或新建文件,并将光标置于第一行首
vi +n filename :打开文件,并将光标置于第n行首
vi + filename :打开文件,并将光标置于最后一行首
vi +/pattern filename:打开文件,并将光标置于第一个与pattern匹配的串处
vi -r filename :在上次正用vi编辑时发生系统崩溃,恢复filename
vi filename….filename :打开多个文件,依次编辑

移动光标类命令
h :光标左移一个字符
l :光标右移一个字符
space:光标右移一个字符
Backspace:光标左移一个字符
k或Ctrl+p:光标上移一行
j或Ctrl+n :光标下移一行
Enter :光标下移一行
w或W :光标右移一个字至字首
b或B :光标左移一个字至字首
e或E :光标右移一个字j至字尾
) :光标移至句尾
( :光标移至句首
}:光标移至段落开头
{:光标移至段落结尾
nG:光标移至第n行首
n+:光标下移n行
n-:光标上移n行
n$:光标移至第n行尾
H :光标移至屏幕顶行
M :光标移至屏幕中间行
L :光标移至屏幕最后行
0:(注意是数字零)光标移至当前行首
$:光标移至当前行尾

屏幕翻滚类命令
Ctrl+u:向文件首翻半屏
Ctrl+d:向文件尾翻半屏
Ctrl+f:向文件尾翻一屏
Ctrl+b;向文件首翻一屏
nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。

插入文本类命令
i :在光标前
I :在当前行首
a:光标后
A:在当前行尾
o:在当前行之下新开一行
O:在当前行之上新开一行
r:替换当前字符
R:替换当前字符及其后的字符,直至按ESC键
s:从当前光标位置处开始,以输入的文本替代指定数目的字符
S:删除指定数目的行,并以所输入文本代替之
ncw或nCW:修改指定数目的字
nCC:修改指定数目的行

删除命令
ndw或ndW:删除光标处开始及其后的n-1个字
do:删至行首
d$:删至行尾
ndd:删除当前行及其后n-1行
x或X:删除一个字符,x删除光标后的,而X删除光标前的
Ctrl+u:删除输入方式下所输入的文本

搜索及替换命令 :
/pattern:从光标开始处向文件尾搜索pattern
?pattern:从光标开始处向文件首搜索pattern
n:在同一方向重复上一次搜索命令
N:在反方向上重复上一次搜索命令
:s/p1/p2/g:将当前行中所有p1均用p2替代
:n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代
:g/p1/s//p2/g:将文件中所有p1均用p2替换

选项设置
all:列出所有选项设置情况
term:设置终端类型
ignorance:在搜索中忽略大小写
list:显示制表位(Ctrl+I)和行尾标志($)
number:显示行号
report:显示由面向行的命令修改过的数目
terse:显示简短的警告信息
warn:在转到别的文件时若没保存当前文件则显示NO write信息
nomagic:允许在搜索模式中,使用前面不带“\”的特殊字符
nowrapscan:禁止vi在搜索到达文件两端时,又从另一端开始
mesg:允许vi显示其他用户用write写到自己终端上的信息

最后行方式命令
:n1,n2 co n3:将n1行到n2行之间的内容拷贝到第n3行下
:n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下
:n1,n2 d :将n1行到n2行之间的内容删除
:w :保存当前文件
:e filename:打开文件filename进行编辑
:x:保存当前文件并退出
:q:退出vi
:q!:不保存文件并退出vi
:!command:执行shell命令command
:n1,n2 w!command:将文件中n1行至n2行的内容作为command的输入并执行之,若不指
定n1,n2,则表示将整个文件内容作为command的输入
:r!command:将命令command的输出结果放到当前行 。

http://dev2dev.bea.com.cn/bbs/school/guide/webser/2005042001.html

1.3 LDAP Security
  
LDAP是轻量级目录服务(Lightweight Directory Access Protocol)。越来越多的应用开始采用LDAP作为后端用户存储。在安全上,LDAP Security是基于ACL(Access Control List)的,它通过给一个用户组分配LDAP 操作资源(比如对一个子树的查询,修改等)来最终完成权限的控制。因此在LDAP中,授权工作是以用户组为单位进行的。一个用户组一般来说是拥有如下一组属性的LDAP Entry:


图1-3-1

  其中objectclass可以为groupOfUniqueNames或者groupOfNames,它们对应的组成员属性分别是uniquemember和member。如果是动态组,objectclass为groupOfURLs。动态组一般应用在成员可以通过某种业务逻辑运算来决定的情况下。比如,经理为ZHANGSAN的全部员工。下面是一个典型的动态组,memberURL属性定义了哪些entry属于该组:


图1-3-2

  从图1-3-1中我们可以看出,用户WANTXIAOMING,ZHANGSAN,LISI属于组HR Managers。这种组和成员的关系是通过属性uniquemember来决定的。同时LADP Group 支持嵌套,即一个组可以是另外一个组的成员,比如我们将Accounting Managers组分配给HR Managers组作为其成员:


图1-3-3

  这样将表示Accounting Managers中的成员,同时也是组HR Managers的成员。通过这种层级关系可以使权限分配变的更加灵活。

  下面是一些名词的解释,希望大家对LDAP有更好的理解:
  a) Objectclass —— LDAP对象类,抽象上的概念类似与一般我们理解的class。根据不同的objectclass,我们可以判断这个entry是否属于某一个类型。比如我们需要找出LDAP中的全部用户:(objectclass=person)再比如我们需要查询全部的LDAP组:(objectclass=groupOfUniqueNames)

  b) Entry —— entry可以被称为条目,或者节点,是LDAP中一个基本的存储单元;可以被看作是一个DN和一组属性的集合。 属性可以定义为多值或者单值。

  c) DN —— Distinguished Name,LDAP中entry的唯一辨别名,一般有如下的形式:uid=ZHANGSAN, ou=staff, ou=people, o=examples。LDAP中的entry只有DN是由LDAP Server来保证唯一的。

  d) LDAP Search filter ——使用filter对LDAP进行搜索。 Filter一般由 (attribute=value) 这样的单元组成,比如:(&(uid=ZHANGSAN)(objectclass=person)) 表示搜索用户中,uid为ZHANGSAN的LDAP Entry.再比如:(&(|(uid= ZHANGSAN)(uid=LISI))(objectclass=person)),表示搜索uid为ZHANGSAN, 或者LISI的用户;也可以使用*来表示任意一个值, 比如(uid=ZHANG*SAN),搜索uid值以 ZHANG开头SAN结尾的Entry。更进一步,根据不同的LDAP属性匹配规则,可以有如下的Filter: (&(createtimestamp>=20050301000000)(createtimestamp<=20050302000000)),表示搜索创建时间在20050301000000和20050302000000之间的entry。
  Filter中 “&” 表示“与”;“!”表示“非”;“|”表示“或”。根据不同的匹配规则,我们可以使用“=”,“~=”,“>=”以及“<=”,更多关于LDAP Filter读者可以参考LDAP相关协议:http://www.ietf.org/rfc/rfc2254.txt

  e) Base DN —— 执行LDAP Search时一般要指定basedn,由于LDAP是树状数据结构,指定basedn后,搜索将从BaseDN开始,我们可以指定Search Scope为:只搜索basedn(base),basedn直接下级(one level),和basedn全部下级(sub tree level)。

  下面是一个典型的LDAP Tree结构,右侧显示Entry uid=ZHANGSAN, ou=staff, ou=people, o=examples的属性,该entry代表了一个名字叫张三的用户:


3 了解WebLogic LDAP Authentication Provider
  
现在我们有信心了解一下WebLogic LDAP Authentication Provider的工作原理了。这里将以WebLogic提供的iPlanet Authentication Provider的配置为例进行说明。在这里也需要明确说明一下,为了方便进行描述,我们将实际属于LoginModule的行为也一并归结到Provider中。没有单独将两个的行为分开,目的是为了突出整个完整的过程。

3.1 iPlanet Authentication Provider配置


图3-1-1

  从上图可以看出我们需要指定LDAP服务器的地址,端口,连接LDAP使用的Principal(不同于前面讨论的Principal,这个Principal实际是一个连接LDAP的用户,也就是一个LDAP 中用户Entry的 DN,它必须要有相关的LDAP 搜索等权限)和Credential(一般来说就是口令)。
  再看下面关于Users的配置:


图3-1-2

3.1.1 User Object Class —— 前面已经对objectclass进行过说明,指明LDAP Entry属于哪一类
3.1.2 User Name Attribute —— 用户登录帐号在LDAP Entry中的属性,一般为UID或者cn
3.1.3 User Base DN —— 所有的用户将会放置到这个子树下面,因此在Provider中对用户进行的搜索将会从这个basedn开始
3.1.4 User Search Scope —— 指定搜索范围为Basedn的直接一级或者全部下级
3.1.5 User From Name Filter —— 使用这个filter可以搜索出用户信息。其中%u将会被用户输入的登录帐号替换,从而查询中LDAP中的用户信息


图3-1-3

3.1.6 Group Base DN —— 从该Base DN开始搜索用户组
3.1.7 Group From Name Filter —— %g将会被组的名字替换,通过该filter可以搜索出符合条件的LDAP Group
3.1.8 Static group name attribute —— 组名字的属性,属性cn对应的值就是组的名字


图3-1-4

3.1.9 Static Member DN Attribute —— 静态成员属性,通过该属性可以判断一个Entry是否属于一个组
3.1.10 Static Group DNs From Member DN Filter —— 通过该filter可以找出用户属于哪些组
3.1.11 Dynamic Group —— 动态组是在运行时根据某种业务逻辑,来决定成员隶属关系的LDAP Group

什么是LDAP?
LDAP的英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,
但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP,这对访问Internet是必须的。LDAP
的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。现在LDAP技术不仅
发展得很快而且也是激动人心的。在企业范围内实现LDAP可以让运行在几乎所有计算机平台上的所有的应
用程序从LDAP目录中获取信息。LDAP目录中可以存储各种类型的数据:电子邮件地址、邮件路由信息、人力
资源数据、公用密匙、联系人列表,等等。通过把LDAP目录作为系统集成中的一个重要环节,可以简化员工
在企业内部查询信息的步骤,甚至连主要的数据源都可以放在任何地方。

LDAP目录的优势

如果需要开发一种提供公共信息查询的系统一般的设计方法可能是采用基于WEB的数据库设计方式,即前端
使用浏览器而后端使用WEB服务器加上关系数据库。后端在Windows的典型实现可能是Windows NT + IIS + Acess
数据库或者是SQL服务器,IIS和数据库之间通过ASP技术使用ODBC进行连接,达到通过填写表单查询数据的功能;

后端在Linux系统的典型实现可能是Linux+ Apache + postgresql,Apache和数据库之间通过PHP3提供的函数进
行连接。使用上述方法的缺点是后端关系数据库的引入导致系统整体的性能降低和系统的管理比较繁琐,因为需
要不断的进行数据类型的验证和事务的完整性的确认;并且前端用户对数据的控制不够灵活,用户权限的设置一
般只能是设置在表一级而不是设置在记录一级。

目录服务的推出主要是解决上述数据库中存在的问题。目录与关系数据库相似,是指具有描述性的基于属性的记
录集合,但它的数据类型主要是字符型,为了检索的需要添加了BIN(二进制数据)、CIS(忽略大小写)、CES
(大小写敏感)、TEL(电话型)等语法(Syntax),而不是关系数据库提供的整数、浮点数、日期、货币等类型,
同样也不提供象关系数据库中普遍包含的大量的函数,它主要面向数据的查询服务(查询和修改操作比一般是大于
10:1),不提供事务的回滚(rollback)机制,它的数据修改使用简单的锁定机制实现All-or-Nothing,它的目标
是快速响应和大容量查询并且提供多目录服务器的信息复制功能。

现在该说说LDAP目录到底有些什么优势了。现在LDAP的流行是很多因数共同作用的结果。可能LDAP最大的优势是:
可以在任何计算机平台上,用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易
定制应用程序为它加上LDAP的支持。

LDAP协议是跨平台的和标准的协议,因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上,LDAP
得到了业界的广泛认可,因为它是Internet的标准。产商都很愿意在产品中加入对LDAP的支持,因为他们根本不用
考虑另一端(客户端或服务端)是怎么样的。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器(或
者还可能是具有LDAP界面的关系型数据库),因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器
进行交互。与LDAP不同的是,如果软件产商想在软件产品中集成对DBMS的支持,那么通常都要对每一个数据库服务
器单独定制。不象很多商用的关系型数据库,你不必为LDAP的每一个客户端连接或许可协议付费 大多数的LDAP服务
器安装起来很简单,也容易维护和优化。

LDAP服务器可以用“推”或“拉”的方法复制部分或全部数据,例如:可以把数据“推”到远程的办公室,以增加
数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能,数据库
产商就会要你支付额外的费用,而且也很难管理。

LDAP允许你根据需要使用ACI(一般都称为ACL或者访问控制列表)控制对数据读和写的权限。例如,设备管理员可
以有权改变员工的工作地点和办公室号码,但是不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数
据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完成的,所以不用担心在客
户端的应用程序上是否要进行安全检查。

LDAP(Lightweight Directory Acess Protocol)是目录服务在TCP/IP上的实现(RFC 1777 V2版和RFC 2251

V3版)。它是对X500的目录协议的移植,但是简化了实现方法,所以称为轻量级的目录服务。在LDAP中目录是按照
树型结构组织,目录由条目(Entry)组成,条目相当于关系数据库中表的记录;条目是具有区别名DN(Distinguished

Name)的属性(Attribute)集合,DN相当于关系数据库表中的关键字(Primary

Key);属性由类型(Type)和多个值(Values)组成,相当于关系数据库中的域(Field)由域名和数据类型组成,
只是为了方便检索的需要,LDAP中的Type可以有多个Value,而不是关系数据库中为降低数据的冗余性要求实现的各
个域必须是不相关的。LDAP中条目的组织一般按照地理位置和组织关系进行组织,非常的直观。LDAP把数据存放在
文件中,为提高效率可以使用基于索引的文件数据库,而不是关系数据库。LDAP协议集还规定了DN的命名方法、存
取控制方法、搜索格式、复制方法、URL格式、开发接口等

LDAP对于这样存储这样的信息最为有用,也就是数据需要从不同的地点读取,但是不需要经常更新。

例如,这些信息存储在LDAP目录中是十分有效的:

l 公司员工的电话号码簿和组织结构图

l 客户的联系信息

l 计算机管理需要的信息,包括NIS映射、email假名,等等

l 软件包的配置信息

l 公用证书和安全密匙

什么时候该用LDAP存储数据

大多数的LDAP服务器都为读密集型的操作进行专门的优化。因此,当从LDAP服务器中读取数据的时候会比从专门为
OLTP优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化,大多数的LDAP目录服务器
并不适合存储需要需要经常改变的数据。例如,用LDAP服务器来存储电话号码是一个很好的选择,但是它不能作为
电子商务站点的数据库服务器。

如果下面每一个问题的答案都是“是”,那么把数据存在LDAP中就是一个好主意。

l 需要在任何平台上都能读取数据吗?

l 每一个单独的记录项是不是每一天都只有很少的改变?

l 可以把数据存在平面数据库(flat database)而不是关系型数据库中吗?换句话来说,也就是不管什么范式不
范式的,把所有东西都存在一个记录中(差不多只要满足第一范式)。

最后一个问题可能会唬住一些人,其实用平面数据库去存储一些关系型的数据也是很一般的。例如,一条公司员工
的记录就可以包含经理的登录名。用LDAP来存储这类信息是很方便的。一个简单的判断方法:如果可以把保数据存
在一张张的卡片里,就可以很容易地把它存在LDAP目录里。


安全和访问控制

LDAP提供很复杂的不同层次的访问控制或者ACI。因这些访问可以在服务器端控制,这比用客户端的软件保证数据的
安全可安全多了。

用LDAP的ACI,可以完成:

l 给予用户改变他们自己的电话号码和家庭地址的权限,但是限制他们对其它数据(如,职务名称,经理的登录名,
等等)只有“只读”权限。

l 给予“HR-admins"组中的所有人权限以改变下面这些用户的信息:经理、工作名称、员工号、部门名称和部门号。
但是对其它域没有写权限。

l 禁止任何人查询LDAP服务器上的用户口令,但是可以允许用户改变他或她自己的口令。

l 给予经理访问他们上级的家庭电话的只读权限,但是禁止其他人有这个权限。

l 给予“host-admins"组中的任何人创建、删除和编辑所有保存在LDAP服务器中的与计算机主机有关的信息

l 通过Web,允许“foobar-sales"组中的成员有选择地给予或禁止他们自己读取一部分客户联系数据的读权限。这
将允许他们把客户联系信息下载到本地的笔记本电脑或个人数字助理(PDA)上。(如果销售人员的软件都支持LDAP,
这将非常有用)

l 通过Web,允许组的所有者删除或添加他们拥有的组的成员。例如:可以允许销售经理给予或禁止销售人员改变Web
页的权限。也可以允许邮件假名(mail aliase)的所有者不经过IT技术人员就直接从邮件假名中删除或添加用户。
“公用”的邮件列表应该允许用户从邮件假名中添加或删除自己(但是只能是自己)。也可以对IP地址或主机名加以
限制。例如,某些域只允许用户IP地址以192.168.200.*开头的有读的权限,或者用户反向查找DNS得到的主机名必须
为*.foobar.com。

LDAP目录树的结构

LDAP目录以树状的层次结构来存储数据。如果你对自顶向下的DNS树或UNIX文件的目录树比较熟悉,也就很容易掌握
LDAP目录树这个概念了。就象DNS的主机名那样,LDAP目录记录的标识名(Distinguished Name,简称DN)是用来读取
单个记录,以及回溯到树的顶部。后面会做详细地介绍。

为什么要用层次结构来组织数据呢?原因是多方面的。下面是可能遇到的一些情况:

l 如果你想把所有的美国客户的联系信息都“推”到位于到西雅图办公室(负责营销)的LDAP服务器上,但是你不想
把公司的资产管理信息“推”到那里。

l 你可能想根据目录树的结构给予不同的员工组不同的权限。在下面的例子里,资产管理组对“asset-mgmt"部分有完
全的访问权限,但是不能访问其它地方。

l 把LDAP存储和复制功能结合起来,可以定制目录树的结构以降低对WAN带宽的要求。位于西雅图的营销办公室需要每
分钟更新的美国销售状况的信息,但是欧洲的销售情况就只要每小时更新一次就行了。

刨根问底:基准DN

LDAP目录树的最顶部就是根,也就是所谓的“基准DN"。基准DN通常使用下面列出的三种格式之一。假定我在名为FooBar
的电子商务公司工作,这家公司在Internet上的名字是foobar.com。

o="FooBar, Inc.", c=US

(以X.500格式表示的基准DN)

在这个例子中,o=FooBar, Inc. 表示组织名,在这里就是公司名的同义词。c=US 表示公司的总部在美国。以前,一般
都用这种方式来表示基准DN。但是事物总是在不断变化的,现在所有的公司都已经(或计划)上Internet上。随着
Internet的全球化,在基准DN中使用国家代码很容易让人产生混淆。现在,X.500格式发展成下面列出的两种格式。

o=foobar.com

(用公司的Internet地址表示的基准DN)

这种格式很直观,用公司的域名作为基准DN。这也是现在最常用的格式。

dc=foobar, dc=com

(用DNS域名的不同部分组成的基准DN)

就象上面那一种格式,这种格式也是以DNS域名为基础的,但是上面那种格式不改变域名(也就更易读),而这种格式
把域名:foobar.com分成两部分 dc=foobar, dc=com。在理论上,这种格式可能会更灵活一点,但是对于最终用户来说
也更难记忆一点。考虑一下foobar.com这个例子。当foobar.com和gizmo.com合并之后,可以简单的把“dc=com"当作基
准DN。把新的记录放到已经存在的dc=gizmo, dc=com目录下,这样就简化了很多工作(当然,如果foobar.com和wocket.edu
合并,这个方法就不能用了)。如果LDAP服务器是新安装的,我建议你使用这种格式。再请注意一下,如果你打算使用活动
目录(Actrive Directory),Microsoft已经限制你必须使用这种格式。

更上一层楼:在目录树中怎么组织数据

在UNIX文件系统中,最顶层是根目录(root)。在根目录的下面有很多的文件和目录。象上面介绍的那样,LDAP目录也是
用同样的方法组织起来的。

在根目录下,要把数据从逻辑上区分开。因为历史上(X.500)的原因,大多数LDAP目录用OU从逻辑上把数据分开来。OU
表示“Organization Unit",在X.500协议中是用来表示公司内部的机构:销售部、财务部,等等。现在LDAP还保留ou=这
样的命名规则,但是扩展了分类的范围,可以分类为:ou=people, ou=groups, ou=devices,等等。更低一级的OU有时用
来做更细的归类。例如:LDAP目录树(不包括单独的记录)可能会是这样的:

dc=foobar, dc=com

ou=customers

ou=asia

ou=europe

ou=usa

ou=employees

ou=rooms

ou=groups

ou=assets-mgmt

ou=nisgroups

ou=recipes

单独的LDAP记录

DN是LDAP记录项的名字

在LDAP目录中的所有记录项都有一个唯一的“Distinguished Name",也就是DN。每一个LDAP记录项的DN是由两个部分
组成的:相对DN(RDN)和记录在LDAP目录中的位置。

RDN是DN中与目录树的结构无关的部分。在LDAP目录中存储的记录项都要有一个名字,这个名字通常存在cn(Common Name)
这个属性里。因为几乎所有的东西都有一个名字,在LDAP中存储的对象都用它们的cn值作为RDN的基础。如果我把最喜欢的
吃燕麦粥食谱存为一个记录,我就会用cn=Oatmeal Deluxe作为记录项的RDN。

l 我的LDAP目录的基准DN是dc=foobar,dc=com

l 我把自己的食谱作为LDAP的记录项存在ou=recipes

l 我的LDAP记录项的RDN设为cn=Oatmeal Deluxe

上面这些构成了燕麦粥食谱的LDAP记录的完整DN。记住,DN的读法和DNS主机名类似。下面就是完整的DN:

cn=Oatmeal Deluxe,ou=recipes,dc=foobar,dc=com

举一个实际的例子来说明DN

现在为公司的员工设置一个DN。可以用基于cn或uid(User ID),作为典型的用户帐号。例如,FooBar的员工Fran Smith
(登录名:fsmith)的DN可以为下面两种格式:

uid=fsmith,ou=employees,dc=foobar,dc=com

(基于登录名)

LDAP(以及X.500)用uid表示“User ID",不要把它和UNIX的uid号混淆了。大多数公司都会给每一个员工唯一的登录名,
因此用这个办法可以很好地保存员工的信息。你不用担心以后还会有一个叫Fran Smith的加入公司,如果Fran改变了她的
名字(结婚?离婚?或宗教原因?),也用不着改变LDAP记录项的DN。

cn=Fran Smith,ou=employees,dc=foobar,dc=com

(基于姓名)

可以看到这种格式使用了Common Name(CN)。可以把Common Name当成一个人的全名。这种格式有一个很明显的缺点就是:
如果名字改变了,LDAP的记录就要从一个DN转移到另一个DN。但是,我们应该尽可能地避免改变一个记录项的DN。

定制目录的对象类型

你可以用LDAP存储各种类型的数据对象,只要这些对象可以用属性来表示,下面这些是可以在LDAP中存储的一些信息:

l 员工信息:员工的姓名、登录名、口令、员工号、他的经理的登录名,邮件服务器,等等。

l 物品跟踪信息:计算机名、IP地址、标签、型号、所在位置,等等。

l 客户联系列表:客户的公司名、主要联系人的电话、传真和电子邮件,等等。

l 会议厅信息:会议厅的名字、位置、可以坐多少人、电话号码、是否有投影机。

l 食谱信息:菜的名字、配料、烹调方法以及准备方法。

因为LDAP目录可以定制成存储任何文本或二进制数据,到底存什么要由你自己决定。LDAP目录用对象类型
(object classes)的概念来定义运行哪一类的对象使用什么属性。在几乎所有的LDAP服务器中,你都要根据
自己的需要扩展基本的LDAP目录
的功能,创建新的对象类型或者扩展现存的对象类型。

LDAP目录以一系列“属性对”的形式来存储记录项,每一个记录项包括属性类型和属性值(这与关系型数据库
用行和列来存取数据有根本的不同)。下面是我存在LDAP目录中的一部分食谱记录:

dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com

cn: Instant Oatmeal Deluxe

recipeCuisine: breakfast

recipeIngredient: 1 packet instant oatmeal

recipeIngredient: 1 cup water

recipeIngredient: 1 pinch salt

recipeIngredient: 1 tsp brown sugar

recipeIngredient: 1/4 apple, any type

请注意上面每一种配料都作为属性recipeIngredient值。LDAP目录被设计成象上面那样为一个属性保存多个值的,
而不是在每一个属性的后面用逗号把一系列值分开。

因为用这样的方式存储数据,所以数据库就有很大的灵活性,不必为加入一些新的数据就重新创建表和索引。更
重要的是,LDAP目录不必花费内存或硬盘空间处理“空”域,也就是说,实际上不使用可选择的域也不会花费你
任何资源。
作为例子的一个单独的数据项

让我们看看下面这个例子。我们用Foobar, Inc.的员工Fran Smith的LDAP记录。这个记录项的格式是LDIF,用来
导入和导出LDAP目录的记录项。

dn: uid=fsmith, ou=employees, dc=foobar, dc=com

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

objectclass: foobarPerson

uid: fsmith

givenname: Fran

sn: Smith

cn: Fran Smith

cn: Frances Smith

telephonenumber: 510-555-1234

roomnumber: 122G

o: Foobar, Inc.

mailRoutingAddress: fsmith@foobar.com

mailhost: mail.foobar.com

userpassword: {crypt}3×1231v76T89N

uidnumber: 1234

gidnumber: 1200

homedirectory: /home/fsmith

loginshell: /usr/local/bin/bash

属性的值在保存的时候是保留大小写的,但是在默认情况下搜索的时候是不区分大小写的。某些特殊的属性
(例如,password)在搜索的时候需要区分大小写。

让我们一点一点地分析上面的记录项。

dn: uid=fsmith, ou=employees, dc=foobar, dc=com

这是Fran的LDAP记录项的完整DN,包括在目录树中的完整路径。LDAP(和X.500)使用uid(User ID),不要
把它和UNIX的uid号混淆了。

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

objectclass: foobarPerson

可以为任何一个对象根据需要分配多个对象类型。person对象类型要求cn(common name)和sn(surname)
这两个域不能为空。persion对象类型允许有其它的可选域,包括givenname、telephonenumber,等等。
organizational Person给person加入更多的可选域,inetOrgPerson又加入更多的可选域(包括电子邮件信息)。
最后,foobarPerson是为Foobar定制的对象类型,加入了很多定制的属性。

uid: fsmith

givenname: Fran

sn: Smith

cn: Fran Smith

cn: Frances Smith

telephonenumber: 510-555-1234

roomnumber: 122G

o: Foobar, Inc.

以前说过了,uid表示User ID。当看到uid的时候,就在脑袋里想一想“login"。

请注意CN有多个值。就象上面介绍的,LDAP允许某些属性有多个值。为什么允许有多个值呢?假定你在用
公司的LDAP服务器查找Fran的电话号码。你可能只知道她的名字叫Fran,但是对人力资源处的人来说她的
正式名字叫做Frances。因为保存了她的两个名字,所以用任何一个名字检索都可以找到Fran的电话号码、
电子邮件和办公房间号,等等。

mailRoutingAddress: fsmith@foobar.com

mailhost: mail.foobar.com

就象现在大多数的公司都上网了,Foobar用Sendmail发送邮件和处理外部邮件路由信息。Foobar把所有用户
的邮件信息都存在LDAP中。最新版本的Sendmail支持这项功能。

Userpassword: {crypt}3×1231v76T89N

uidnumber: 1234

gidnumber: 1200

gecos: Frances Smith

homedirectory: /home/fsmith

loginshell: /usr/local/bin/bash

注意,Foobar的系统管理员把所有用户的口令映射信息也都存在LDAP中。FoobarPerson类型的对象具有这
种能力。再注意一下,用户口令是用UNIX的口令加密格式存储的。UNIX的uid在这里为uidnumber。提醒你一下,
关于如何在LDAP中保存NIS信息,有完整的一份RFC。在以后的文章中我会谈一谈NIS的集成。

LDAP复制

LDAP服务器可以使用基于“推”或者“拉”的技术,用简单或基于安全证书的安全验证,复制一部分或者所
有的数据。

例如,Foobar有一个“公用的”LDAP服务器,地址为ldap.foobar.com,端口为389。Netscape Communicator
的电子邮件查询功能、UNIX的“ph"命令要用到这个服务器,用户也可以在任何地方查询这个服务器上的员工
和客户联系信息。公司的主LDAP服务器运行在相同的计算机上,不过端口号是1389。

你可能即不想让员工查询资产管理或食谱的信息,又不想让信息技术人员看到整个公司的LDAP目录。为了解决
这个问题,Foobar有选择地把子目录树从主LDAP服务器复制到“公用”LDAP服务器上,不复制需要隐藏的信息。
为了保持数据始终是最新的,主目录服务器被设置成即时“推”同步。这些种方法主要是为了方便,而不是安全,
因为如果有权限的用户想查询所有的数据,可以用另一个LDAP端口。

假定Foobar通过从奥克兰到欧洲的低带宽数据的连接用LDAP管理客户联系信息。可以建立从ldap.foobar.com:1389
到munich-ldap.foobar.com:389的数据复制,象下面这样:

periodic pull: ou=asia,ou=customers,o=sendmail.com

periodic pull: ou=us,ou=customers,o=sendmail.com

immediate push: ou=europe,ou=customers,o=sendmail.com

“拉”连接每15分钟同步一次,在上面假定的情况下足够了。“推”连接保证任何欧洲的联系信息发生了变化就
立即被“推”到Munich。
用上面的复制模式,用户为了访问数据需要连接到哪一台服务器呢?在Munich的用户可以简单地连接到本地服务
器。如果他们改变了数据,本地的LDAP服务器就会把这些变化传到主LDAP服务器。然后,主LDAP服务器把这些变化
“推”回本地的“公用”LDAP服务器保持数据的同步。这对本地的用户有很大的好处,因为所有的查询(大多数是读)都在本地的服务器上进行,速度非常快。当需要改变信息的时候,最终用户不需要重新配置客户端的软件,因为LDAP目录服务器为他们完成了所有的数据交换工作。