??xml version="1.0" encoding="utf-8" standalone="yes"?>日本在线丨区,在线看国产视频,蜜臀久久99精品久久久画质超高清http://www.aygfsteel.com/lmsun/category/2788.htmlzh-cnWed, 28 Feb 2007 20:24:43 GMTWed, 28 Feb 2007 20:24:43 GMT60JAAS Security in Actionhttp://www.aygfsteel.com/lmsun/articles/11031.htmlmy javamy javaThu, 25 Aug 2005 05:43:00 GMThttp://www.aygfsteel.com/lmsun/articles/11031.htmlhttp://www.aygfsteel.com/lmsun/comments/11031.htmlhttp://www.aygfsteel.com/lmsun/articles/11031.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/11031.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/11031.htmlThis 10-Minute Solution provides a brief introduction to the JAAS (pronounced "Jazz") architecture, API, and programming model. It covers both authentication and authorization with JAAS, providing full working code examples that demonstrate JAAS security in action.



How do I implement security, one of the most important aspects of today's software applications, into my Java environment when most security implementations are inflexible, proprietary systems?



The Java Authentication and Authorization Service (JAAS) is a flexible, standardized API that supports runtime pluggability of security modules.

What Is JAAS?
According to Sun's Web site, "The Java Authentication and Authorization Service (JAAS) is a set of packages that enables services to authenticate and enforce access controls upon users. It implements a Java version of the standard Pluggable Authentication Module (PAM) framework, and supports user-based authorization."

In practice, JAAS represents the new Java security standard, as it has formally been added to the JDK 1.4 code base. From an architectural standpoint, JAAS implements a Java version of the Pluggable Authentication Module (PAM) framework. First released in May 2000 by The PAM Forum, the framework is a modularized architecture designed to support the seamless exchange of one security protocol component for another. The framework allows multiple authentication technologies and/or authentication approaches to be added without changing or interfering with any of the existing login services. PAM can be used to integrate login services with various authentication technologies, such as RSA, DCE, Kerberos, S/Key, and even to support smart card-based authentication systems.

Authenticating with JAAS
JAAS authentication is deployed in a pluggable manner, using code modules that implement certain interfaces. This enables Java applications to remain decoupled from the underlying authentication technologies. Additional authentication protocols and updated authentication technologies can be plugged in at runtime without modifying the application or recompiling the source code.

The JAAS Authentication API is quite extensive. The key interfaces and classes that you need to familiarize yourself with are as follows:

  • Callback ?Implementations of this interface encapsulate information (usernames, passwords, error and warning messages) that is exchanged between security services and a CallbackHandler.
  • CallbackHandler ?An application implements a CallbackHandler and passes it to underlying security services to facilitate interaction between the security services and the application.
  • LoginContext ?The LoginContext class provides the basic methods used to authenticate Subjects in a neutral manner, decoupled from the underlying authentication technology.
  • LoginModule ?Authentication technology providers implement this interface to provide a particular type of authentication via a pluggable module.
  • Principal ?The Principal interface represents the abstract notion of a principal, which can be used to represent any unique entity (individual, corporation, organization, login id, social security number, etc.) that can be authenticated.
  • Subject ?A Subject object represents a grouping of related information for a single entity, such as a person. One or more Principals are bound to a subject. Each Principal represents one identity for the subject (name, social security #, etc.). A Subject also maintains security-related attributes (passwords and cryptographic keys, for example).
  • Authorization with JAAS
    JAAS authorization is built on top of JAAS authentication. It augments the existing code-centric access controls that were introduced with the Java 2 platform (JDK 1.2.x) with new user-centric access controls. In this way, JAAS authorization allows you to grant permissions based not on just what code is running but also on who is running it.

    After a user has been authenticated by JAAS, the authorization API associates the Subject (created to represent the authenticated entity) with an appropriate access control context. Whenever the Subject attempts a restricted operation (database access, local file access, etc.), the Java runtime consults the policy file to determine which Principal(s) may perform the operation. If the Subject in question contains the designated Principal, the Java runtime allows the operation. Otherwise, it throws an exception.

    You don't need to import additional packages to access the JAAS authorization features, because JAAS authorization is built on top of JAAS authentication. In addition to the classes and interfaces used in the authentication piece, one additional interface is of interest for the simple example in this Solution:

  • PrivilegedAction ?This interface defines only one member, a method named run(). It accepts no parameters and returns type Object. A class wanting to restrict access to one or more actions implements this interface and puts the calls to the restricted functions within its run() method.
  • See JAAS in Action
    Included with this Solution is a downloadable zip file that contains all the source code and class files necessary to see JAAS authentication and authorization in action.

    advertisement

    Authentication Files

  • SimpleAuth.java ?This file contains the main() method. It creates a LoginContext object by passing in a LoginModule configuration id ("JAAS_Module") and an instance of the CallbackHandler interface. The LoginContext reads a configuration file, looking for the configuration ID. Upon finding a match, it instantiates the specified LoginModules. Each LoginModule is initialized with a Subject, a CallbackHandler, shared LoginModule state, and LoginModule-specific options. Finally, the login process is kicked off by calling the login() method on the LoginContext object (which is implemented by the LoginModule class).
  • SimpleJAAS.config ?This file associates configuration IDs (simple text string) with LoginModules and optional properties.
  • SimpleCallbackHandler.java ?This file implements the CallbackHandler interface and handles the callback events passed by the security service components.
  • SimpleLoginModule.java ?This file implements the LoginModule interface and interfaces between the user and the CallbackHandler to authenticate the user. It uses two arrays to maintain the set of possible usernames and passwords. The passwords are then compared by passing a PasswordCallback instance to the SimpleCallbackHandler and using the readPassword() method defined in the SimpleCallbackHandler class.
  • SimplePrincipal.java ?This file provides a bare-bones implementation of the Principal interface.

    Authorization Files

  • SimpleAuthz.java ?This class is identical to the SimpleAuth.java class in all but one respect. After authenticating the user, it attempts a privileged action. To do this, the code obtains a reference to the current Subject and calls the doAsPrivileged() method from that object reference. We pass the Subject reference and an instance of the SimpleAction class into this method. The Java runtime then will take the supplied Subject reference and attempt to execute the privileged action defined within the run() method of the SimpleAction class.
  • SimpleAction.java ?This class implements the PrivilegedAction interface and defines a single method, run(). It attempts to perform a few actions that are restricted to privileged users (as defined by the policy file). If the Subject has the appropriate privileges to perform these actions, the method will execute without any trouble. Otherwise, it throws an exception.
  • SimpleJAAS.policy ?This file defines the activities for which permission has been granted and which code has permission to perform them (code-level access). These grant statements can further be narrowed to allow only a particular Principal (user-level access).

    To test the application, run the provided script and indicate whether you want to test just authentication ('run auth') or authentication and authorization ('run authz'). When prompted for a username and password, provide any of the following pairs:

  • guest, sesame
  • user1, pass1
  • user2, pass2

    You will receive verbose output if the debug option in the config file debug property is set to 'true'. The output will be limited if it is set to 'false'.



  • my java 2005-08-25 13:43 发表评论
    ]]>
    Implement Single Sign-on with JAAS http://www.aygfsteel.com/lmsun/articles/11029.htmlmy javamy javaThu, 25 Aug 2005 05:29:00 GMThttp://www.aygfsteel.com/lmsun/articles/11029.htmlhttp://www.aygfsteel.com/lmsun/comments/11029.htmlhttp://www.aygfsteel.com/lmsun/articles/11029.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/11029.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/11029.html 
    JAAS is an ideal tool for access control in a multi-user environment where users must be granted varying privileges. Learn how to implement single sign-on for multiple Web applications based on JAAS.  

    With the increasing use of distributed systems, users often need to access multiple resources to finish a single business transaction. Traditionally, users have had to sign on to all these systems, each of which may involve different usernames and authentication requirements. With the introduction of the single sign-on technique, users can login once and be authenticated for all systems involved in a given business transaction.

    Although the single sign-on concept is appealing, implementing it is not at all easy because enterprise systems often have varying security requirements and a wide range of underlying technologies on which they are deployed. In Java environments, Java Authentication and Authorization Service (JAAS) has made implementation easier. JAAS, a significant enhancement to the Java security architecture, is an ideal tool for access control in a multi-user environment where users must be granted varying privileges. Unlike the standard JDK security model, which is code-source-based permission checking, JAAS controls access to resources with both code-source-based and user/role-based permission checking. Most importantly, the "pluggable" and stackable login module architecture that JAAS defines makes it instrumental in supporting legacy security implementations on different technologies and serves as a useful mechanism for implementing single sign-on.

    Single sign-on can be implemented for applications that are deployed either locally or over a network. In the case of a network, after the user logs into the primary domain, an encrypted secure token is created and sent over the wire to other applications. In local networks, user credential data is exchanged directly between applications. Both deployment options share two key challenges: passing user credential information between involved domains and translating this information.

    An enterprise application can be comprised of several Web applications, each of which may depend on different technologies and data stores to retrieve the user information it needs to authenticate the user and determine his or her privilege. If a business transaction crosses the Web application boundary, the user needs to log into each Web application and present similar credentials to each of the application authentication services.

    This article demonstrates a single sign-on implementation for multiple Web applications based on JAAS. Specifically, it introduces an approach to achieving single sign-on between Web applications deployed on the same application server.

    The JAAS Authentication Framework
    Before I get into the single sign-on implementation, let's examine what's under the JAAS hood. The JAAS framework is composed of two interdependent parts: an authentication part and an authorization part. The authentication part is used to determine the identity of the user, while the authorization part checks the permission of the authenticated user and controls resource access based on the user's privileges.

     

    A user has to be authenticated before he/she can access any sensitive resources. After the user is successfully authenticated, his/her principal is populated in the associated Subject class and the permissions granted to the principal are then checked by the authorization component.

    Pluggable Authentication Module (PAM) Framework
    The JAAS authentication framework is based on Pluggable Authentication Module (PAM). JAAS authentication is performed in a pluggable fashion that allows an application to add more authentication modules. Java applications can remain independent from underlying authentication technologies, and thus both legacy and new authentication technologies can be seamlessly configured without requiring modifications to the application itself.

    The JAAS authentication framework allows applications to define any number of login modules in the configuration file. The JAAS framework invokes these login modules in the order they were specified. Applications can also specify a flag to each login module to indicate the relative importance of that module. The overall authentication depends on the combined results of these individual authentication modules.

    PAM allows different Web applications to authenticate users against its own data store, be it an LDAP server, relational database, NT domain, or even a file. PAM is the feature that enables developers to implement single sign-on among Web applications deployed on the same application server.

    LoginModule
    The LoginModule interface gives developers the ability to implement different kinds of authentication technologies that can be plugged under an application. For example, one type of LoginModule may perform a username/password-based form of authentication. Other LoginModules may interface to hardware devices such as smart cards or biometric devices.

    The ability to pass optional share information between login modules is the key feature I employ to achieve single sign-on among Web applications. User credential information can be shared using this option and since it is not sent across the network, there is no need for extra effort to maintain the integrity and security of the credential information.

    JAAS Implementation of Single Sign-On for Multiple Web Apps
    Now let's get to the implementation of single sign-on based on JAAS for Web applications deployed on the same server. To make it easier for discussion, I use an LDAP-based login module as an example.

     

    Login Configuration for Single Sign-On
    When multiple Web applications are deployed on a single application server instance, usually each Web application authenticates users based on its own data store. One Web application may use a relational database to store user security information and another may use an LDAP server to authenticate users. The JAAS PAM architecture allows an enterprise application to define a stack of login modules, each of which is independent and communicates to its own data source. To achieve single sign-on, each Web application defines its own login module and all modules are stacked in a certain order in the login configuration file.

    JAAS defines a configuration interface, which a user can implement to store configuration data in a file or a database. In this discussion, I assume a file-based login configuration and I use a Logistics enterprise application as an example. The Logistics enterprise application contains two Web applications: carrier Web application and shipper Web application. Carrier users log into the carrier Web application to report location and movement events for shipment and Shipper users log into the shipper Web application to query the delivery events of shipment.

    If a 3PL (third-part logistics) uses this Logistics enterprise application, employees of the 3PL will need to log into both Web applications to maintain and query shipment status on behalf of both the carrier and shipper. To achieve single sign-on in this situation based on JAAS, the login configuration file needs to be defined as follows:

    
    LogisticsEnterpriseApplication
    {
       com.cysive.framework.security.ldap.LDAPLoginModule 
    required name=CarrierSecurityDomain; com.cysive.framework.security.ldap.LDAPLoginModule
    required name=ShipperSecurityDomain useSharedState=true; };

    Notice two LDAP login modules are defined: one for the carrier Web application and one for the shipper Web application. These two login modules may communicate to the same LDAP server or different ones, depending on the configuration (using name attribute to link to the particular configuration block) for the LDAP server. For single sign-on, the flags for both login modules are specified as required (other flags include optional, sufficient, and requisite), which means the user must be successfully authenticated by both LDAP servers.

    Additionally, the attribute useSharedState is specified. If it is true, this LoginModule retrieves the username and password from the module's shared state, using "javax.security.auth.login.name" and "javax.security.auth.login.password" as the respective keys. The retrieved values are used for authentication. The username and password are set into shared state by LoginContext before invoking the login method of the login module instance. The useSharedState attribute allows all login modules to share the user's credential information, which is captured only once.

    An XML-based Configuration for Login Module
    When the login module communicates with the data store, be it a database or an LDAP server, it requires certain configurations for common or special attributes. Using the LDAP login module for example, it will at least know the hostname of the LDAP server. Depending on your implementation, you may need different configuration parameters. Listing 1 shows a sample configuration block for the two LDAP login modules defined in the previous sections.

    This configuration needs to be loaded when the application server starts up so it can be shared by Web applications loaded later. I will not discuss each entry in detail but instead focus on the parts that are relevant to single sign-on.

    While each block is being loaded, the initializer class is invoked. The initializer reads all the properties and registers them in the domain manager class with the name specified by the name attribute. The value of this name attribute is the same as the one specified in the login configuration file. This is how the login module entry is associated with its configuration block.

    If the configuration is simple, you can even configure it when you define the login module in the configuration file, such as:

    
    com.cysive.framework.security.ldap.LDAPLoginModule 
    required DriverName="oracle.jdbc.driver.OracleDriver"
    InitialCapacity="0" MaxCapacity="10" Properties="user=cymbio;password=cymbio
    URL="jdbc:oracle:thin:@jtao1:1521:jtao1";

    However, if your initialization for a login module requires substantial setup, a separate initialization block is the preferred approach.

    In the two sample LDAP initialization blocks, the carrier security domain configures the login module to talk to the carrier.cysive.com LDAP server while the shipper login module communicates with shipper.cysive.com. You can easily substitute one of them with a relational database login module if user security information is stored in a database.

    Passing Shared Security Token Between Login Modules
    JAAS defines a LoginContext class, which provides a context for all login modules defined for an application. Its login method iterates through all login modules and calls each login module's login method. It determines the overall authentication result by combining the results of the login method returned from each login module.

    In the login method of LoginContext, each login module defined in the configuration file is instantiated and then is passed four parameters using the initialize method of the login module (See Listing 2, exception checking is omitted for smaller code).

    The following are the four parameters the initialize method passes:

  • Subject is populated with principal and credential information by the login module
  • CallBackHandler is used by the login module for capturing user credential information (such as username/password)
  • Shared state map will be used for passing user security information between login modules
  • Options are additional name/value pairs defined in the configuration file and are meaningful only for that particular login module.

    The shared state map parameter is key to implementing single sign-on. After the first login module captures the user credential information, such as user name and password, it puts the information into the shared state map and passes it to other login modules on the list. The other login module has an optional parameter specified (useSharedState=true), so it simply gets the shared security information back and authenticates against its own security data store. Listing 3 shows a code excerpt for the LoginModule that implements this (exception checking has been omitted to reduce the length of the code segment).

    ReMapping of Security Information
    Using a shared state map to pass security information between login modules to achieve single sign-on requires the user to have the same credential information across all domains. I could enforce the same username and password for all domains that involve single sign-on, but that may limit legacy security systems that have varying user name and password requirements. For example, different authentication mechanisms may have their own distinctive password requirements with regard to length, characters allowed, and so forth. These requirements make using the same username and password for multiple login modules problematic.

    In their paper, "Making Login Services Independent of Authentication Technologies", Vipin Samar and Charlie Lai proposed a mapping mechanism that solves this problem. This mapping enables the user's primary password to be used for encrypting the user's secondary passwords. Once the primary password is verified, the login module obtains the password by decrypting the mechanism-specific encrypted password with the primary password. It then authenticates it to its data store. How the password is encrypted depends completely on the module implementation. To use password mapping, Samar and Lai also suggest two more optional attributes be passed to the login module:

  • use_mapped_pass - Use the password-mapping scheme to get the actual password for this module. The module should not ask for the password if the user cannot be authenticated by the first password. Note that the process for decrypting passwords is left completely to the module.
  • try_mapped_pass - This attribute is the same as use_mapped_pass, except that if the primary password is not valid, the module should prompt the user for it.

    Shared Map Is Key
    Single sign-on for multiple Web applications is useful when business transactions cross session context boundaries. The pluggable and stackable login module infrastructure provided by JAAS allows enterprise applications to authenticate users with different login mechanisms and technologies. Exchanging security information between login modules using the shared map is the key to implementing single sign-on.



  • my java 2005-08-25 13:29 发表评论
    ]]>
    Cross-Domain Single Sign-On Authentication with JAAS http://www.aygfsteel.com/lmsun/articles/11028.htmlmy javamy javaThu, 25 Aug 2005 05:23:00 GMThttp://www.aygfsteel.com/lmsun/articles/11028.htmlhttp://www.aygfsteel.com/lmsun/comments/11028.htmlhttp://www.aygfsteel.com/lmsun/articles/11028.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/11028.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/11028.html
    Cross-Domain Single Sign-On Authentication with JAAS

    Leverage your existing JAAS enterprise security system to provide SSO across multiple subsystems. Implementing this J2EE security model will take your security architecture to the next level. 
    ingle sign-on (SSO) is a very hot topic. Businesses in every industry are eager to integrate legacy systems into newer applications, and SSO can alleviate the headaches users experience when trying to manage a long list of user names and passwords for various systems. Enter the Java Authentication and Authorization Service (JAAS).

    As I wrote in a DevX 10-Minute Solution, "JAAS Security in Action": JAAS “is a flexible, standardized API that supports runtime pluggability of security modules.?If you are unfamiliar with JAAS, I recommend reading that article and reviewing the downloadable code before continuing, as this article assumes an understanding of JAAS. It takes the next logical step from a security architecture standpoint: integrating your J2EE security model to provide SSO across multiple subsystems by leveraging your existing LDAP directory server, database server, or any other enterprise security system.

    Before going any further, let's clarify how this article uses the term "domain": It refers to security domains (LDAP, database, etc.) and not Web domains. If you are interested in using JAAS to share authentication information between multiple Web applications, read the article "Implement Single Sign-on with JAAS" written by James Tao in October of 2002. Additionally, if you are interested in Web applications that exist across firewalls and participate in some sort of Web service exchange, read the joint Web Single Sign-On Identify specifications that Microsoft and Sun recently published.

    Securing the Enterprise

    Single sign-on allows users to enter security credentials once (typically by logging into a workstation or a Web application) and have those credentials propagated to each local and network application the user accesses during his or her session. Local applications exchange authentication information directly, while remote network applications exchange authentication information across the network via encrypted security tokens.

    Regardless of whether the deployment scenario is local, across a network, or a combination of the two, the security challenges are the same: sharing credentials between domains, correctly interpreting the credentials once received, and managing different sets of privileges across these domains (e.g., a user could be a manager within one system, a power user in another system, and a normal user in a third).

    Finally, the heterogeneous nature of most enterprise systems creates some unique challenges for SSO security architectures. Each application within the enterprise could be comprised of different technologies, operate on different platforms, access disparate data sources, and except slightly different authentication credentials for the same principal (user). In spite of these overwhelming obstacles, JAAS combined with LDAP provides a solid framework for designing and implementing a robust SSO enterprise security framework.



    The Architecture

    The backbone of a J2EE SSO architecture is the standard J2EE security model, which is well documented in other places (see Related Resources in the left-hand column). In a nutshell, J2EE security consists of principals (users) who are associated with roles (groups) that are given privileges (authorization). These roles with assigned privileges are further organized under the concept of a realm (domain). Each realm maps users and groups to privileges within its own scope. The key to providing SSO is seamlessly connecting these different realms (and corresponding enterprise systems) without requiring the user to enter authentication information each time he or she wishes to access another system.

    Consider the following example: A user logs in to an application via HTTP, authenticating herself against the server's security realm (MemoryRealm, JDBCRealm, JAASRealm, etc). The user then uses the Web application's search feature, querying the database and returning a resultlist. The database could then require that the middleware platform authenticate against the DB before performing the transaction. Finally, the user wants to update information stored in her directory server (LDAP). This is a privileged action, requiring the user to first authenticate against the LDAP realm before modifying any directory data. All three of these realms likely require slightly different authentication schemes (different user IDs, passwords, additional security tokens, etc.), but the same principal (user) is accessing them each time.

    Java can provide an elegant SSO solution for the above scenario (and any number of similar scenarios) using JAAS's pluggable login module architecture. JAAS login modules facilitate the smooth integration of J2EE's security framework with various systems and their respective heterogeneous authentication mechanisms (OS, LDAP, database, etc.). These modules can be configured to share authentication data and designed to correctly identify users and roles by mapping principals and roles—even across domains with differing security schemas.

    The Components

    The application components required for a JAAS SSO solution include the following:
    • Two or more enterprise systems that need a common, integrated security framework
    • Two or more JAAS login module classes to drive the authentication exchange between agent (user or subsystem) and callback handler
    • One or more JAAS callback handler classes to respond to callback events in order to perform the actual authentication procedure(s)
    • A login configuration file to define how JAAS will manage authentication across multiple security realms (configuration could even be stored in an XML file or database)

    Assembling these components and connecting all of the pieces correctly can be a bit daunting the first time. Be sure to thoroughly test your JAAS authentication components individually with each system prior to attempting to link them and share authentication information. The process of packaging, deploying, and testing your solution should go something like this:

    1. Write a login module (implement LoginModule, a subtype of LoginContext) and a callback handler (implement CallbackHandler interface) for authenticating against a single enterprise system (LDAP, database, etc.).
    2. Define the configuration for your login module (this could be as simple as an XML file containing a single statement).
    3. Define a UI (Web, console, or rich GUI) to capture authentication data, and then pass it to your login module.
    4. If this is a server-based solution (HTTP, sockets, RMI, etc.), define the J2EE security (constraints and roles) on the server in the usual way (web.xml or application.xml), and then define a realm on the server (server.xml) that references the JAAS login module configuration (accomplished via the appName attribute). Local (non-server) solutions will simply rely upon JAAS and a J2SE policy file to define security constraints and permissions.
    5. Start the server (specifying the login configuration file via a Java command line attribute), launch the client, and provide authentication credentials. Debug and modify as necessary to resolve any errors.
    6. Rinse and repeat. Continue this process as necessary until each enterprise system can successfully be authenticated via a JAAS login module.
    7. Finally, hook all of the individual authentication pieces together. The following section addresses this issue.

    The above list simply gives you a brief overview of the process. For more details on how to actually accomplish these steps, please consult the links in the Related Resources space.



    Sharing Authentication Across Domains

    The JAAS configuration file mentioned earlier defines configuration IDs, which contain one or more LoginModule definitions and corresponding attributes. The key to sharing authentication information across security domains is to have a single JAAS configuration ID that lists multiple login modules, with the second, third, and following modules specifying the useSharedState attribute as true (allowing security credentials to be shared).

    The following is a sample configuration involving two systems, LDAP and an Oracle database, included within the same SSO architecture:

    
    BasicAuth {
    	com.xyz.ldap.LDAPLoginModule 
    required name=LDAPSecurityDomain;
    };
    
    DBAccessAuth {
    	com.xyz.ldap.LDAPLoginModule 
    required name=LDAPSecurityDomain;
    com.xyz.db.OracleLoginModule
    required name=OracleSecurityDomain
    useSharedState=true;
    };
    

    Two configurations are defined (BasicAuth and DBAccessAuth) to provide the flexibility of authenticating a user against one or both systems.

    To implement this, the first system (LDAP) is treated as the primary system. The corresponding login module should be setup as the security realm for the J2EE container (using the BasicAuth configuration). Once a user has authenticated against the primary system (see Figure 1), she can have her security credentials propagated to the other system(s) in the chain (using the DBAccessAuth) that require authenticated access (see Figure 2).

    Click to enlarge
    Figure 1: Initial System Authentication/Authorization Process Through JAAS

    Click to enlarge
    Figure 2: Subsequent System Authentication/Authorization Process Through JAAS

    This simple example contains only two subsystems, but a more complex system could include as many JAAS login modules as systems that need to share security credentials. The key difference between how authentication occurs with the two subsystems is that the primary system has JAAS authentication handled automatically (the container manages the process since the login module is configured as a security realm). The secondary subsystem (as well as any subsequent systems) must be called programmatically via the login() method of LoginContext:

    
    LoginContext ctx = new LoginContext( "DBAccessAuth", new SimpleCallbackHandler() );
    

    The above example assumed a fairly ideal situation in which the user's security credentials were the same for both subsystems. In real life, this is rarely the case. You often find yourself needing to integrate legacy systems with new applications, each requiring different credentials. You can accomplish this by using the original authentication information to unlock a secured datastore that houses secondary authentication information for the specified principal (one or more sets of credentials). Once you've obtained this other authentication information, you then can use it to authenticate transparently against any secondary systems. (For more details on this approach, read Vipin Samar and Charlie Lai's article (PDF): "Making Login Services Independent of Authentication Technologies".)

    Voila! Single sign-on across multiple security domains by mapping primary credentials gathered from the user to secondary credentials stored on the server and used to authenticate transparently against other enterprise systems.

    Single SSO in Your Enterprise Framework

    SSO is a popular feature of modern enterprise systems. Unfortunately, implementing SSO can be difficult and error-prone. This brief article provides a high-level overview and guide for architects, developers, and/or managers who are interested in implementing a SSO security architecture within their current enterprise frameworks.

    Kyle Gabhart is a Senior Principal Information Systems Architect with L-3 Communications, Link Simulation and Training Division. Author of dozens of articles and books, Kyle has served as a consultant, trainer, and mentor for Fortune 500 companies, including American Express, J.P. Morgan-Chase, Goldman Sachs, and Verizon. Find Kyle on the Web at http://www.gabhart.com and reach him by email at rkgabhart@link.com.



    my java 2005-08-25 13:23 发表评论
    ]]>
    JCIFS NTLM HTTP Authenticationhttp://www.aygfsteel.com/lmsun/articles/10585.htmlmy javamy javaSat, 20 Aug 2005 05:45:00 GMThttp://www.aygfsteel.com/lmsun/articles/10585.htmlhttp://www.aygfsteel.com/lmsun/comments/10585.htmlhttp://www.aygfsteel.com/lmsun/articles/10585.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10585.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10585.htmlNtlmSsp classes directly. This Filter scales very well primarily because sessions are multiplexed over transports. But this functionality is not without caveats. Note: This functionality is a non-conformant extension to HTTP conceived entirely by Microsoft. It inappropriately uses HTTP headers and therefore may not work with all Servlet containers or may stop working with a new release of your application server. Also, this flavor of password encryption is not very secure so under no circumstances should it be used to authenticate clients on the Internet.

    Note: Don't forget to restart the container after changing jCIFS init-parameters. JCIFS must use the container class loader and jCIFS properties are only read once when jCIFS classes are initialized.

    Installation and Setup

    Put the latest jCIFS jar file in the lib/ directory of your webapp [1]. Because jCIFS properties are loaded once when the jCIFS classes are first accessed, it is necessary to actually stop and restart the container if any jCIFS properties have been changed. Below are two web.xml configurations. Note that the jcifs.smb.client.domain and jcifs.smb.client.domainController properties are mutually exclusive.

    Production web.xml Example

    A minimalistic web.xml file with filter and filter-mapping directives might look like the following:
    <filter>
        <filter-name>NtlmHttpFilter</filter-name>
        <filter-class>jcifs.http.NtlmHttpFilter</filter-class>
    
        <init-param>
            <param-name>jcifs.smb.client.domain</param-name>
            <param-value>NYC-USERS</param-value>
        </init-param>
        <init-param>
            <param-name>jcifs.netbios.wins</param-name>
            <param-value>10.169.10.77,10.169.10.66</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>NtlmHttpFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    This filter section illustrates the setup for authenticating clients against the domain NYC-USERS. This is suitable for large numbers of concurrent users as jCIFS will cycle through domain controllers and use an alternate WINS server if necessary.

    The above will authenticate users accessing all content against the domain NYC-USERS. The WINS server 10.169.10.77 will be queried to resolve NYC-USERS to an IP address of a domain controller. If that WINS server is not responding, 10.169.10.66 will be queried.

    Alternate web.xml Example

    The below example filter section illistrates how to specify the IP address of the domain controller specifically using the jcifs.http.domainController property. The target machine does not need to be a real domain controller -- it could be just a workstation. Also illustrated below is the jcifs.smb.client.logonShare property. This will cause jCIFS to attempt to access the resource \\192.168.2.15\JCIFSACL when authenticating users. By creating that share and changing the Access Control List only certain users or groups of users will have access to your website.
    <filter>
        <filter-name>NtlmHttpFilter</filter-name>
        <filter-class>jcifs.http.NtlmHttpFilter</filter-class>
    
        <init-param>
            <param-name>jcifs.http.domainController</param-name>
            <param-value>192.168.2.15</param-value>
        </init-param>
        <init-param>
            <param-name>jcifs.smb.client.logonShare</param-name>
            <param-value>JCIFSACL</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>NtlmHttpFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    This filter section illustrates the setup for authenticating against a JCIFSACL share for testing or a site with a small number of concurrent users (e.g. 1000)

    Either a jcifs.smb.client.domain or jcifs.smb.client.domainController property is required. This will be suitable to authenticate clients that are members of the specified domain as well as other domains with which it has trusts relationships.

    Running the NtlmHttpAuthExample.java example should be a suitable test of the Filter.

    NTLM HTTP Authentication Example

    NYC-USERS\MIALLEN successfully logged in

    Please submit some form data using POST

    field1 = hello
    The significance of the POST test is that after negotiating NTLM HTTP Authentication once, IE will not POST any form data until it has negotiated the password hashes again.

    If the NTLM HTTP Authentication Filter is not enabled something like the following will be displayed:
    null successfully logged in
    Notice the user was permitted access. Unlike this example, developers might add an additional check to make sure getRemoteUser does not return null.

    Non MSIE Clients and "Basic" Authentication

    NTLM HTTP authentication is only supported by MSIE transparently. Mozilla 1.6 supports NTLM HTTP negotiation but it will always prompt the user for credentials by default (although the Mozilla documentation on Integrated Authentication describes how to make it transparent to the user for trusted sites). For other clients it is possible to use basic authentication to pass NTLM password credentials. This is strongly discouraged if SSL is not being used because it sends these credentials in plain text. It would not be difficult for another user to download and install a program to "snoop" LAN traffic and obtain other user's passwords.

    Regardless, this functionality has been added to the NtlmHttpFilter and NtlmServlet (for pre 2.3 servlet containers) although it is disabled by default. To enable this capability set the jcifs.http.basicRealm, jcifs.http.enableBasic, and jcifs.http.insecureBasic properties described in the table below.

    JCIFS Properties Meaningful to NTLM HTTP Authentication

    All parameters that begin with 'jcifs.' will be set as jCIFS properties which means that any jCIFS properties may be used as init parameters. These properties must be set before jCIFS classes are used. For a complete list of jCIFS properties refer to the overview page of the API documentation. Here is a select subset of jCIFS properties with additional notes in the context of NTLM HTTP Authentication.

    jcifs.smb.client.domain The NT domain against which clients should be authenticated. Generally it is necessary to also set the jcifs.netbios.wins parameter or a domain controller may not be found. This parameter will be ignored for NTLM HTTP authentication purposes if a jcifs.http.domainController property is specified (although they can be used together for "preauthenctication" as described in the SMB Signatures and Windows 2003 section below).
    jcifs.http.domainController The IP address of any SMB server that should be used to authenticate HTTP clients with the NtlmHttpFilter class. If this is not specified the jcifs.smb.client.domain 0x1C NetBIOS group name will be queried. If these queries fail an UnknownHostException will be thrown. It is not necessary for this to specify a real domain controller. The IP address of a workstation will do for simple purposes.
    jcifs.http.basicRelm The realm for basic authentication. This property defaults to 'jCIFS'.
    jcifs.http.enableBasic Setting this property to true enables basic authentication over HTTPS only.
    jcifs.http.insecureBasic Setting this property to true enables basic authentication over plain HTTP. This configuration passes user credentials in plain text over the network. It should not be used in environment where security is required.
    jcifs.http.loadBalance If a jcifs.smb.client.domain property is specified (and domainController is not specified) the NtlmHttpFilter will query for domain controllers by name. If this property is true the Filter will rotate through the list of domain controllers when authenticating users. The default value is true. The jcifs.netbios.lookupRespLimit property can also be used to limit the number of domain controllers used.
    jcifs.netbios.lookupRespLimit The 0x1C NetBIOS name query returns a list of domain controllers. It is believed that the servers at the top of this list should be favored. This property limits the range of servers returned by name queries. The default value is 5 meaning the top 5 domain controllers will be used.
    jcifs.netbios.wins The IP address of the WINS server. This is required when accessing hosts on different subnets (like a domain controller by name) and it is highly recommended if a wins server is available.
    jcifs.smb.client.laddr The ip address of the local interface the client should bind to if it is different from the default. For example if jCIFS is used to authenticate clients on one interface and the domain controller for those clients is accessible only on another interface of a webserver with two NICs it may be necessary to specify which interface jCIFS should use.
    jcifs.netbios.laddr The ip address of the local interface the client should bind to for name queries if it is different from the default. Likely set to the same as the above property.
    jcifs.smb.client.attrExpirationPeriod Attributes of a file are cached for attrExpirationPeriod milliseconds. The default is 5000 but the NetworkExplorer servlet will attempt to set this property to 120000. Otherwise, when listing large directories, the attributes of SmbFiles may expire within the default period resulting in a large number of additional network messages and severe performance degradation.
    jcifs.smb.client.soTimeout To prevent the client from holding server resources unnecessarily, sockets are closed after this time period if there is no activity. This time is specified in milliseconds. The default is 15000 however when NTLM HTTP Authentication is used, the NtlmHttpFilter will attempt to set this value to 5 minutes so that frequent calls to SmbSession.logon() do not provoke redundant messages being submitted to the domain controller. If it is not desirable to cache password hashes set this value back to 15000.
    jcifs.netbios.cachePolicy When a NetBIOS name is resolved with the NbtAddress class it is cached to reduce redundant name queries. This property controls how long, in seconds, these names are cached. The default is 30 seconds, 0 is no caching, and -1 is forever. When NTLM HTTP Authentication is used, NtlmHttpFilter will attempt to set this value to 20 minutes so that frequent queries for a domain controller will be cached.

    Must Restart The Container

    If you change any jcifs properties or replace an existing jcifs jar file with a different one, the container must be restarted. This is because most jcifs properties are retrieved only once when classes are first loaded.

    Tomcat

    Tomcat requires that all filter directives be adjacent to one another, all filter-mapping directives appear adjacent to one another, all servlet directives ... and so on. This is because Tomcat validates the web.xml against the deployment descriptor DTD.

    MalformedURLException: unknown protocol: smb

    If you get the following exception try upgrading to jcifs-0.7.0b12 or later. Also read the FAQ.
    Exception MalformedURLException: unknown protocol: smb
          at java.net.URL.(URL.java:480)
          at java.net.URL.(URL.java:376)
          at java.net.URL.(URL.java:330)
          at jcifs.smb.SmbFile.(SmbFile.java:355)
          ...
    

    Transparent Authentication and the Network Password Dialog

    If the Filter is working properly the Network Password Dialog should never appear. However there are several requirements that must be met for a web browser to transparently negotiate credentials using NTLM HTTP authenication. If any of these requirements are not met, the default behavior is to present the user with the Network Password dialog. The requirements are:

    1. The client must be logged into the Windows NT domain identified by the jcifs.smb.client.domain parameter (or the domain of the host identified by the jcifs.smb.client.domainController parameter if it is used instead). The client may also be logged into a domain that has a trust relationship with the target domain. Indeed it is not uncommon to configure workstations to join a different domain from those of users. Note that Windows 95/98/ME systems cannot really join a domain but can be configured to do so enough to participate in transparent NTLM HTTP authentication.
    2. Only Internet Explorer will negotiate NTLM HTTP authentication transparently. Mozilla will always prompt the user for credentials (someone please notify us when/if this is not true anymore). At the time this FAQ was written it was not known which other browsers, if any, can negotiate NTLM HTTP authenication transparently.
    3. Either the target URL must contain a server in the local domain (e.g. ws1.mycompany.com) or the client's security settings must be changed (e.g. Tools > Internet Options > Security > Local Intranet > Sites > Advanced > add your site). If the URL does not contain a URL in the defined IntrAnet zone (e.g. not an IP address), Internet Explorer will assume that the server is in the IntErnet zone and present the user with the Network Password dialog. It would be very bad if a server on the Internet could convince IE to send it your NTLM password hashes. These hashes are easily cracked with brute force dictionary attacks. To prevent this scenario, IE tries to distinguish between Intranet sites and Internet sites. Here are some important notes to consider when deploying a site with NTLM HTTP Authentication regardless of whether or not jCIFS is used to do it.
    4. The user's credentials must be valid. For example if the account has expired, been disabled or is locked out the Network Password dialog will appear. To determine which error was at fault it will be necessary to modify the NtlmHttpFilter to inspect the SmbAuthException in doFilter.
    5. The jCIFS client must support the lmCompatibility level necessary for communication with the domain controller. If the server does not permit NTLMv1 try to set jcifs.smb.lmCompatibility = 3.

    Personal Workstation AD Security Policy

    If your Active Directory security policy requires that users only log into the domain from their personal workstations JCIFS will fail to authenticate and the server security log will have entries like "\\JCIFS10_40_4A cannot be authorized". This occurs because the domain controller is failing to resolve the dynamically generated "calling name" submitted by the client during protocol negotiation. To get around this it is necessary to set the jcifs.netbios.hostname property to a valid NetBIOS name that can be resolved by the NetBIOS name service (e.g. WINS) and add that name to the AD security policy as a permitted client.

    For example, you can set this property using an init-paremeter in the web.xml file for the NTLM HTTP filter as follows:
    <init-parameter>
        <parameter-name>jcifs.netbios.hostname</parameter-name>
        <parameter-value>MYHOSTNAME</parameter-value>
    </init-parameter>
    

    HTTP POST and Protecting Sub-Content

    Once IE has negotiated NTLM HTTP authentication it will proactively renegotiate NTLM for POST requests for all content associated with the server (based on IP?). Therefore when using HTTP POST requests it is not possible to restrict access to some content on the server as IE will attempt and fail to negotiate NTLM (standard IE error page?). This is a protocol limitation and there does not appear to be a way to convince IE to stop proactively negotiating for POST requests once it has been determined that the server is capable of negotiating NTLM authentication.

    SMB Signatures and Windows 2003

    If the domain controller against which you are authenticating clients requires SMB signatures (Windows 2003 does by default), it is recommended that you provide init-parameters for the jcifs.smb.client.{domain,username,password} to perform "preauthentication" for each transport to a domain contoller so that a proper SMB signing key will be generated. In fact, this may be necessary for proper operation; it has been observed that NT 4.0 does not check the signatures of authentication requests but the behavior has not been confirmed in all environments. If the Filter works for the first authentication but fails with a second user shortly thereafter this would suggest that signing was established but subsequent authentications are failing due to the lack of a good signing key. Additionally, without a proper signing key certain requests (SMB_COM_TREE_DISCONNECT and SMB_COM_LOGOFF_ANDX) will cause signature verification failures (although they are harmless to the client).

    A third solution for signature issues is to change the jcifs.smb.client.ssnLimit to 1. This will require that every authentication uses a separate transport. Because the MAC signing key is only used on SMB communication occuring after the initial authentication, signing will be effectively ignored. However, this solution will significantly reduce scalability as each authentication will open it's own transport. For this reason the second solution of using a "workstation account" to preauthenticate transports is considered the superior method and should be used by default for servers that requires signatures.

    NTLM HTTP Authentication Protocol Details

    The NTLM HTTP Authentication process is described well in these documents:

    http://davenport.sourceforge.net/ntlm.html
    http://www.innovation.ch/java/ntlm.html

    The process can be summarized as a 3 request/response "handshake". So doGet() will be called three times. The first is the initial request. A 401 Unauthorized is sent back to which IE submits a special message encoded in a header. Another 401 Unauthorized is sent back after which IE submits the password hashes. This is where jCIFS comes in. The password hashes alone are useless. You must check their authenticity against the password database on a server somewhere (actually you can specify the IP of a plain workstation or any other SMB server). Otherwise a user who's workstation is not a member of the domain will get a password dialog into which they could put anything and it would let them in. This is what pretty much all the examples seen in various forums do. Don't be fooled.

    [1] Due to restrictions in how protocol handlers are loaded, if the SMB URL protocol handler is to be used (meaning you want to access SMB resources with smb:// URLs) within your application it is necessary for the jCIFS jar to be loaded by the System class loader. This can usually be achived by placing it in the container lib/ directory. However, for containers that load servlet classes in a child classloaders (Tomcat) this too will cause problems as jCIFS will not be able to load javax.servlet.* classes. To get the filter and the URL protocol handler to operate together requires some experimentation and depends on the container being used.

    my java 2005-08-20 13:45 发表评论
    ]]>
    NTLM Authentication Scheme for HTTPhttp://www.aygfsteel.com/lmsun/articles/10507.htmlmy javamy javaFri, 19 Aug 2005 05:54:00 GMThttp://www.aygfsteel.com/lmsun/articles/10507.htmlhttp://www.aygfsteel.com/lmsun/comments/10507.htmlhttp://www.aygfsteel.com/lmsun/articles/10507.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10507.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10507.htmlIntroduction

    This is an attempt at documenting the undocumented NTLM authentication scheme used by M$'s browsers, proxies, and servers (MSIE and IIS); this scheme is also sometimes referred to as the NT challenge/response (NTCR) scheme. Most of the info here is derived from three sources (see also the Resources section at the end of this document): Paul Ashton's work on the NTLM security holes, the encryption documentation from Samba, and network snooping. Since most of this info is reverse-engineered it is bound to contain errors; however, at least one client and one server have been implemented according to this data and work successfully in conjunction with M$'s browsers, proxies and servers.

    Note that this scheme is not as secure as Digest and some other schemes; it is slightly better than the Basic authentication scheme, however.

    Also note that this scheme is not an http authentication scheme - it's a connection authentication scheme which happens to (mis-)use http status codes and headers (and even those incorrectly).

    NTLM Handshake

    When a client needs to authenticate itself to a proxy or server using the NTLM scheme then the following 4-way handshake takes place (only parts of the request and status line and the relevant headers are shown here; "C" is the client, "S" the server):

        1: C  --> S   GET ...
        
        2: C <--  S   401 Unauthorized
                      WWW-Authenticate: NTLM
        
        3: C  --> S   GET ...
                      Authorization: NTLM <base64-encoded type-1-message>
        
        4: C <--  S   401 Unauthorized
                      WWW-Authenticate: NTLM <base64-encoded type-2-message>
        
        5: C  --> S   GET ...
                      Authorization: NTLM <base64-encoded type-3-message>
        
        6: C <--  S   200 Ok
    

    Messages

    The three messages sent in the handshake are binary structures. Each one is described below as a pseudo-C struct and in a memory layout diagram. byte is an 8-bit field; short is a 16-bit field. All fields are unsigned. Numbers are stored in little-endian order. Struct fields named zero contain all zeroes. An array length of "*" indicates a variable length field. Hexadecimal numbers and quoted characters in the comments of the struct indicate fixed values for the given field.

    The field flags is presumed to contain flags, but their significance is unknown; the values given are just those found in the packet traces.

    Type-1 Message

    This message contains the host name and the NT domain name of the client.

        struct {
            byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
            byte    type;            // 0x01
            byte    zero[3];
            short   flags;           // 0xb203
            byte    zero[2];
    
            short   dom_len;         // domain string length
            short   dom_len;         // domain string length
            short   dom_off;         // domain string offset
            byte    zero[2];
    
            short   host_len;        // host string length
            short   host_len;        // host string length
            short   host_off;        // host string offset (always 0x20)
            byte    zero[2];
    
            byte    host[*];         // host string (ASCII)
            byte    dom[*];          // domain string (ASCII)
        } type-1-message
    
                     0       1       2       3
                 +-------+-------+-------+-------+
             0:  |  'N'  |  'T'  |  'L'  |  'M'  |
                 +-------+-------+-------+-------+
             4:  |  'S'  |  'S'  |  'P'  |   0   |
                 +-------+-------+-------+-------+
             8:  |   1   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            12:  | 0x03  | 0xb2  |   0   |   0   |
                 +-------+-------+-------+-------+
            16:  | domain length | domain length |
                 +-------+-------+-------+-------+
            20:  | domain offset |   0   |   0   |
                 +-------+-------+-------+-------+
            24:  |  host length  |  host length  |
                 +-------+-------+-------+-------+
            28:  |  host offset  |   0   |   0   |
                 +-------+-------+-------+-------+
            32:  |  host string                  |
                 +                               +
                 .                               .
                 .                               .
                 +             +-----------------+
                 |             | domain string   |
                 +-------------+                 +
                 .                               .
                 .                               .
                 +-------+-------+-------+-------+
    
    The host and domain strings are ASCII (or possibly ISO-8859-1), are uppercased, and are not nul-terminated. The host name is only the host name, not the FQDN (e.g. just "GOOFY", not "GOOFY.DISNEY.COM"). The offsets refer to the offset of the specific field within the message, and the lengths are the length of specified field. For example, in the above message host_off = 32 and dom_off = host_off + host_len. Note that the lengths are included twice (for some unfathomable reason).

    Type-2 Message

    This message contains the server's NTLM challenge.

        struct {
            byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
            byte    type;            // 0x02
            byte    zero[7];
            short   msg_len;         // 0x28
            byte    zero[2];
            short   flags;           // 0x8201
            byte    zero[2];
    
            byte    nonce[8];        // nonce
            byte    zero[8];
        } type-2-message
    
                     0       1       2       3
                 +-------+-------+-------+-------+
             0:  |  'N'  |  'T'  |  'L'  |  'M'  |
                 +-------+-------+-------+-------+
             4:  |  'S'  |  'S'  |  'P'  |   0   |
                 +-------+-------+-------+-------+
             8:  |   2   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            12:  |   0   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            16:  |  message len  |   0   |   0   |
                 +-------+-------+-------+-------+
            20:  | 0x01  | 0x82  |   0   |   0   |
                 +-------+-------+-------+-------+
            24:  |                               |
                 +          server nonce         |
            28:  |                               |
                 +-------+-------+-------+-------+
            32:  |   0   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            36:  |   0   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
    
    The nonce is used by the client to create the LanManager and NT responses (see Password Hashes). It is an array of 8 arbitrary bytes. The message length field contains the length of the complete message, which in this case is always 40.

    Type-3 Message

    This message contains the username, host name, NT domain name, and the two "responses".

        struct {
            byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
            byte    type;            // 0x03
            byte    zero[3];
    
            short   lm_resp_len;     // LanManager response length (always 0x18)
            short   lm_resp_len;     // LanManager response length (always 0x18)
            short   lm_resp_off;     // LanManager response offset
            byte    zero[2];
    
            short   nt_resp_len;     // NT response length (always 0x18)
            short   nt_resp_len;     // NT response length (always 0x18)
            short   nt_resp_off;     // NT response offset
            byte    zero[2];
    
            short   dom_len;         // domain string length
            short   dom_len;         // domain string length
            short   dom_off;         // domain string offset (always 0x40)
            byte    zero[2];
    
            short   user_len;        // username string length
            short   user_len;        // username string length
            short   user_off;        // username string offset
            byte    zero[2];
    
            short   host_len;        // host string length
            short   host_len;        // host string length
            short   host_off;        // host string offset
            byte    zero[6];
    
            short   msg_len;         // message length
            byte    zero[2];
    
            short   flags;           // 0x8201
            byte    zero[2];
    
            byte    dom[*];          // domain string (unicode UTF-16LE)
            byte    user[*];         // username string (unicode UTF-16LE)
            byte    host[*];         // host string (unicode UTF-16LE)
            byte    lm_resp[*];      // LanManager response
            byte    nt_resp[*];      // NT response
        } type-3-message
    
                     0       1       2       3
                 +-------+-------+-------+-------+
             0:  |  'N'  |  'T'  |  'L'  |  'M'  |
                 +-------+-------+-------+-------+
             4:  |  'S'  |  'S'  |  'P'  |   0   |
                 +-------+-------+-------+-------+
             8:  |   3   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            12:  |  LM-resp len  |  LM-Resp len  |
                 +-------+-------+-------+-------+
            16:  |  LM-resp off  |   0   |   0   |
                 +-------+-------+-------+-------+
            20:  |  NT-resp len  |  NT-Resp len  |
                 +-------+-------+-------+-------+
            24:  |  NT-resp off  |   0   |   0   |
                 +-------+-------+-------+-------+
            28:  | domain length | domain length |
                 +-------+-------+-------+-------+
            32:  | domain offset |   0   |   0   |
                 +-------+-------+-------+-------+
            36:  |  user length  |  user length  |
                 +-------+-------+-------+-------+
            40:  |  user offset  |   0   |   0   |
                 +-------+-------+-------+-------+
            44:  |  host length  |  host length  |
                 +-------+-------+-------+-------+
            48:  |  host offset  |   0   |   0   |
                 +-------+-------+-------+-------+
            52:  |   0   |   0   |   0   |   0   |
                 +-------+-------+-------+-------+
            56:  |  message len  |   0   |   0   |
                 +-------+-------+-------+-------+
            60:  | 0x01  | 0x82  |   0   |   0   |
                 +-------+-------+-------+-------+
            64:  | domain string                 |
                 +                               +
                 .                               .
                 .                               .
                 +           +-------------------+
                 |           | user string       |
                 +-----------+                   +
                 .                               .
                 .                               .
                 +                 +-------------+
                 |                 | host string |
                 +-----------------+             +
                 .                               .
                 .                               .
                 +   +---------------------------+
                 |   | LanManager-response       |
                 +---+                           +
                 .                               .
                 .                               .
                 +            +------------------+
                 |            | NT-response      |
                 +------------+                  +
                 .                               .
                 .                               .
                 +-------+-------+-------+-------+
    

    The host, domain, and username strings are in Unicode (UTF-16, little-endian) and are not nul-terminated; the host and domain names are in upper case. The lengths of the response strings are 24.

    Password Hashes

    To calculate the two response strings two password hashes are used: the LanManager password hash and the NT password hash. These are described in detail at the beginning of the Samba ENCRYPTION.html document. However, a few things are not clear (such as what the magic constant for the LanManager hash is), so here is some almost-C code which calculates the two responses. Inputs are passw and nonce, the results are in lm_resp and nt_resp.

        /* setup LanManager password */
    
        char  lm_pw[14];
        int   len = strlen(passw);
        if (len > 14)  len = 14;
    
        for (idx=0; idx<len; idx++)
            lm_pw[idx] = toupper(passw[idx]);
        for (; idx<14; idx++)
            lm_pw[idx] = 0;
    
    
        /* create LanManager hashed password */
    
        unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
        unsigned char lm_hpw[21];
        des_key_schedule ks;
    
        setup_des_key(lm_pw, ks);
        des_ecb_encrypt(magic, lm_hpw, ks);
    
        setup_des_key(lm_pw+7, ks);
        des_ecb_encrypt(magic, lm_hpw+8, ks);
    
        memset(lm_hpw+16, 0, 5);
    
    
        /* create NT hashed password */
    
        int   len = strlen(passw);
        char  nt_pw[2*len];
        for (idx=0; idx<len; idx++)
        {
            nt_pw[2*idx]   = passw[idx];
            nt_pw[2*idx+1] = 0;
        }
    
        unsigned char nt_hpw[21];
        MD4_CTX context;
        MD4Init(&context);
        MD4Update(&context, nt_pw, 2*len);
        MD4Final(nt_hpw, &context);
    
        memset(nt_hpw+16, 0, 5);
    
    
        /* create responses */
    
        unsigned char lm_resp[24], nt_resp[24];
        calc_resp(lm_hpw, nonce, lm_resp);
        calc_resp(nt_hpw, nonce, nt_resp);
    

    Helpers:

        /*
         * takes a 21 byte array and treats it as 3 56-bit DES keys. The
         * 8 byte plaintext is encrypted with each key and the resulting 24
         * bytes are stored in the results array.
         */
        void calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
        {
            des_key_schedule ks;
    
            setup_des_key(keys, ks);
            des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) results, ks, DES_ENCRYPT);
    
            setup_des_key(keys+7, ks);
            des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+8), ks, DES_ENCRYPT);
    
            setup_des_key(keys+14, ks);
            des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+16), ks, DES_ENCRYPT);
        }
    
    
        /*
         * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
         * The key schedule ks is also set.
         */
        void setup_des_key(unsigned char key_56[], des_key_schedule ks)
        {
            des_cblock key;
    
            key[0] = key_56[0];
            key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
            key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
            key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
            key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
            key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
            key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
            key[7] =  (key_56[6] << 1) & 0xFF;
    
            des_set_odd_parity(&key);
            des_set_key(&key, ks);
        }
    

    Keeping the connection alive

    As mentioned above, this scheme authenticates connections, not requests. This manifests itself in that the network connection must be kept alive during the second part of the handshake, i.e. between the receiving of the type-2 message from the server (step 4) and the sending of the type-3 message (step 5). Each time the connection is closed this second part (steps 3 through 6) must be repeated over the new connection (i.e. it's not enough to just keep sending the last type-3 message). Also, once the connection is authenticated, the Authorization header need not be sent anymore while the connection stays open, no matter what resource is accessed.

    For implementations wishing to work with M$'s software this means that they must make sure they use either HTTP/1.0 keep-alive's or HTTP/1.1 persistent connections, and that they must be prepared to do the second part of the handshake each time the connection was closed and is reopened. Server implementations must also make sure that HTTP/1.0 responses contain a Content-length header (as otherwise the connection must be closed after the response), and that HTTP/1.1 responses either contain a Content-length header or use the chunked transfer encoding.

    Example

    Here is an actual example of all the messages. Assume the host name is "LightCity", the NT domain name is "Ursa-Minor", the username is "Zaphod", the password is "Beeblebrox", and the server sends the nonce "SrvNonce". Then the handshake is:

        C -> S   GET ...
        
        S -> C   401 Unauthorized
                 WWW-Authenticate: NTLM
        
        C -> S   GET ...
                 Authorization: NTLM TlRMTVNTUAABAAAAA7IAAAoACgApAAAACQAJACAAAABMSUdIVENJVFlVUlNBLU1JTk9S
        
        S -> C   401 Unauthorized
                 WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==
        
        C -> S   GET ...
                 Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHIAAAAYABgAigAAABQAFABAAAAADAAMAFQAAAASABIAYAAAAAAAAACiAAAAAYIAAFUAUgBTAEEALQBNAEkATgBPAFIAWgBhAHAAaABvAGQATABJAEcASABUAEMASQBUAFkArYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADT
        
        S -> C   200 Ok
    

    and the unencoded messages are:

    Type-1 Message:

           0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
       0:  4e 54 4c 4d 53 53 50 00 01 00 00 00 03 b2 00 00  "NTLMSSP........."
      10:  0a 00 0a 00 29 00 00 00 09 00 09 00 20 00 00 00  "....)....... ..."
      20:  4c 49 47 48 54 43 49 54 59 55 52 53 41 2d 4d 49  "LIGHTCITYURSA-MI"
      30:  4e 4f 52                                         "NOR"
    

    Type-2 Message:

           0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
       0:  4e 54 4c 4d 53 53 50 00 02 00 00 00 00 00 00 00  "NTLMSSP........."
      10:  28 00 00 00 01 82 00 00 53 72 76 4e 6f 6e 63 65  "(.......SrvNonce"
      20:  00 00 00 00 00 00 00 00                          "........"
    

    Type-3 Message:

           0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
       0:  4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00  "NTLMSSP........."
      10:  72 00 00 00 18 00 18 00 8a 00 00 00 14 00 14 00  "r..............."
      20:  40 00 00 00 0c 00 0c 00 54 00 00 00 12 00 12 00  "@.......T......."
      30:  60 00 00 00 00 00 00 00 a2 00 00 00 01 82 00 00  "`..............."
      40:  55 00 52 00 53 00 41 00 2d 00 4d 00 49 00 4e 00  "U.R.S.A.-.M.I.N."
      50:  4f 00 52 00 5a 00 61 00 70 00 68 00 6f 00 64 00  "O.R.Z.a.p.h.o.d."
      60:  4c 00 49 00 47 00 48 00 54 00 43 00 49 00 54 00  "L.I.G.H.T.C.I.T."
      70:  59 00 ad 87 ca 6d ef e3 46 85 b9 c4 3c 47 7a 8c  "Y....m..F...<Gz."
      80:  42 d6 00 66 7d 68 92 e7 e8 97 e0 e0 0d e3 10 4a  "B..f}h.........J"
      90:  1b f2 05 3f 07 c7 dd a8 2d 3c 48 9a e9 89 e1 b0  "...?....-<H....."
      a0:  00 d3                                            ".."
    

    For reference, the intermediate hashed passwords are:

    lm_hpw (LanManager hashed password):
    91 90 16 f6 4e c7 b0 0b a2 35 02 8c a5 0c 7a 03 00 00 00 00 00
    nt_hpw (NT hashed password):
    8c 1b 59 e3 2e 66 6d ad f1 75 74 5f ad 62 c1 33 00 00 00 00 00

    Resources

    * LM authentication in SMB/CIFS
    http://www.ubiqx.org/cifs/SMB.html#SMB.8.3
    * A document on cracking NTLMv2 authentication
    http://www.blackhat.com/presentations/win-usa-02/urity-winsec02.ppt
    * Squid's NLTM authentication project
    http://squid.sourceforge.net/ntlm/
    * Encryption description for Samba
    http://de.samba.org/samba/ftp/docs/htmldocs/ENCRYPTION.html
    * Info on the MSIE security hole
    http://oliver.efri.hr/~crv/security/bugs/NT/ie6.html
    * FAQ: NT Cryptographic Password Attacks & Defences
    http://www.ntbugtraq.com/default.asp?sid=1&pid=47&aid=17
    * M$'s hotfix to disable the sending of the LanManager response
    ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40/hotfixes-postSP3/lm-fix
    * A description of M$'s hotfix
    http://www.tryc.on.ca/archives/bugtraq/1997_3/0070.html

    Acknowledgements

    Special thanks to the following people who helped with the collection and debugging of the above information:
     


    my java 2005-08-19 13:54 发表评论
    ]]>
    The NTLM Authentication Protocolhttp://www.aygfsteel.com/lmsun/articles/10503.htmlmy javamy javaFri, 19 Aug 2005 05:52:00 GMThttp://www.aygfsteel.com/lmsun/articles/10503.htmlhttp://www.aygfsteel.com/lmsun/comments/10503.htmlhttp://www.aygfsteel.com/lmsun/articles/10503.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10503.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10503.html阅读全文

    my java 2005-08-19 13:52 发表评论
    ]]>
    在JavaE序中访问Windows׃n文gpȝ http://www.aygfsteel.com/lmsun/articles/10487.htmlmy javamy javaFri, 19 Aug 2005 03:18:00 GMThttp://www.aygfsteel.com/lmsun/articles/10487.htmlhttp://www.aygfsteel.com/lmsun/comments/10487.htmlhttp://www.aygfsteel.com/lmsun/articles/10487.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10487.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10487.html    

    本文涉及的几个关键字解释Q?nbsp;

    SMB: Server Message Block, 用于׃n例如文g、打印机、串口或者是命名道{用于通讯的抽象对象;
    CIFS:  Common Internet File System,  SMB的增强版QWindows 2000/XP实现了该协议Q?BR>JCIFS: 一个实CCIFS的纯Java目Q无MQ何的本地库?/P>

    JCIFS的网址Q?http://jcifs.samba.org/

    下面我们看一个非常简单的例子Q在q行q个例子之前必须准备两台机器A、BQ其中我们A是我们程序运行所在的机器Q而B则是被访问的机器Q仅用B上的Guest用户Q而且A当前的用户不能存在于B机器中,也就是说当我们通过资源理器访?\\B 的时候,会要求输入用户名以及口oQ如下图所C:

     

     

     

     

     

    q个时候A机器上的E序׃能通过例如 \\B\folder\1.txt q样的\径来讉KB机器上共享文件夹folder中的1.txt文gQ也是说Java中自带的File,FileInputStreamcdl不起作用了Q不信? 不信你丫试试

    但是借助于JCIFS你就可以很容易的讉K到文?.txt的内容,我们先来看这个简单的例子Q?/P>

    import jcifs.smb.*;

    public class Demo{
        public static void main(String[] args) throws Exception{
            //user和password换成是B机器上的用户名以及口?BR>        SmbFileInputStream in = new SmbFileInputStream("smb://user:password@B/folder/1.txt" );
            byte[] b = new byte[8192];
            int n;
            while(( n = in.read( b )) > 0 ) {
                System.out.write( b, 0, n );
            }
        }
    }

    ~译q运行这面的例子便可以打印文?1.txt 的内宏V?BR>把上面例子中的密码填写成一个错误的密码再运行程序,便会得到 jcifs.smb.SmbAuthException 异常?BR>
    写文件也是一个道理,关于文g的操作JCIFS提供了这么几个类QSmbFile,SmbFileInputStream,SmbFileOutputStreamQ具体的用户跟Java中对应的cd不多?/P>

    JCIFS中文件的URL也就是smb_urlQ格式ؓQsmb://{user}:{password}@{host}/{path} Q只要填好这个URLQJCIFS׃帮你搞定w䆾验证的事Q粉单的?/P>

    my java 2005-08-19 11:18 发表评论
    ]]>
    用JAVA讉K׃n文gpȝhttp://www.aygfsteel.com/lmsun/articles/10485.htmlmy javamy javaFri, 19 Aug 2005 03:16:00 GMThttp://www.aygfsteel.com/lmsun/articles/10485.htmlhttp://www.aygfsteel.com/lmsun/comments/10485.htmlhttp://www.aygfsteel.com/lmsun/articles/10485.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10485.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10485.html

    [ 2004-8-10 21:49:00 | By: roof ]

    前言

    在Microsoft |?l?p?l?中,SMBQServer Message BlockQ?????块) ??是Windows for Workgroup(WfWg)、Windows 95、Windows NT 和LanManager ??????局 ?|??????????议????用Linux 和Windows NT ???局 ?|??_Samba ??为Linux ??的SMB ??E?? ???E?????包, ?????现Windows 和Linux ?????????I?????机。通用|络文gpȝUCIFS,它事实上是windowsq_文g׃n的标准协议,它是windows explorer,|络d和映网l驱动器的底层实现协议。JAVAh天然的^台无x,使用JAVA可以讉KMcd的服务器或客h上的׃n文gpȝQƈ且编写的软g产品可以q行于Q何^収ͼ因此用JAVA讉K׃n文gpȝ在企业应用中h得天独厚的优ѝ?/P>

    JAVA中的CIFS实现

    Jcifs是CIFS在JAVA中的一个实玎ͼ是sambal织本着linux的精,负责l护开发的一个开源项目。这个项目专注于使用java语言对cifs协议的设计和实现。他们将jcifs设计成ؓ一个完整的Q丰富的Q具有可扩展能力且线E安全的客户端库。这一库可以应用于各种java虚拟问遵循CIFS/SMB|络传输协议的网l资源。类gjava.io.File的接口Ş式,在多U程的工作方式下被证明是有效而容易用的。目前jcifs的最新版本是jcifs-0.8.0bQ你可以在本文最后列出的参考资料中获得下蝲q一cd的网址Q这一版本q支持分布式的文件系l,本文不涉及q一内容?/P>

    JAVA/CIFSE序设计

    如果你曾l用过java的文件操作功能,那么你将很容易掌握jcifs的开发方法。Jcifs通过cM如下的资源url定位一个资源:

    smb://guest:1234@192.168.3.56/share/a.txt

    q个url的开始部分smb:// 说明了这是一个smbcd的urlQ接下来的guest?234分别是访问共享资源的用户名称和密码;@后面是要讉K的资源的L名或IP地址。最后是资源的共享文件夹名称和共享资源名?

    在JAVAE序中,使用如下方式获得一个远E共享文件的句柄Q?

    SmbFile file = new SmbFile("smb://guest:1234@192.168.3.56/share/a.txt");

    q里的句柄不仅限于远E的׃n文gQ还可能是共享文件夹。isFile()Ҏ(gu)和isDirectory()用来判断q个句柄对应的资源的真实属性。如果是׃n文g夹,通过调用它的list()Ҏ(gu)获得其中资源的列表。ListҎ(gu)支持qo器机Ӟ有两U过滤器可供使用Q一U是SmbFileFilter,另一U是SmbFilenameFilterQ这两个在jcifs中作为接口出玎ͼ你可以根据自q需要派生出个性化的过滤器Q实现接口中的acceptҎ(gu)Q以满不同业务的需求?

    SmbFileInputStream是smb文g的输入流Q它的功能是以流的方式打开一个SmbFileQ?

    SmbFileInputStream in = new SmbFileInputStream(file);

    SmbFileInputStream提供readҎ(gu)Q你可以从这个流中读E文件全部的内容?

    xQ你已经掌握了java讉Ksmb文gpȝ的基本方法?

    SmbFileOutputStream是smb文g的输入流Q可以向q程文gpȝ通过smb写入数据Q方法与上面cMQ不再赘q?

    本文后面附带的源代码是一个完整的例子Q它完成功能很简单,是另一台电(sh)脑上指定׃n文g夹下的某些文件拷贝到本机的指定目录下。通过q个例子Q相信你很容易将它移植到你的开发品中?/P>

    W一步,讄q行环境。将源代码解压羃Q将lib目录下的名称为jcifs-0.8.0b.jar的文件加入到你的操作pȝ的classpath中,使示例程序运行时能够扑ֈq个库?/P>

    W二步,在另一台计机上徏立名UCؓshare的共享文件夹,用户名ؓguest,密码也ؓguest。假设这台计机的ip地址?92.168.0.2?/P>

    W三步,在刚才徏立的׃n文g夹下攄两个文gQ名U分别ؓhello.txtQbye.txt。文件的内容无所谓?/P>

    W三步,在本地计机上的C盘跟目录下徏立一个名UCؓtmp的空目录Q置此目录可写?/P>

    W四步,~译q行Sample1.javaQƈq行Q?/P>

    Java Sample1 192.168.3.52 guest guest /share/ c:/tmp/

    查c:\tmp文g?会发现hello.txtq个文g被复制到了本机,而bye.txt没有被复Ӟ因ؓSample1.java中用了qo器,仅允许名UCؓhello开头的文g被拷贝?/P>

    后记

    对共享文件系l的讉K是内部办公系l等涉及到文件迁Uȝ软g产品开发过E中不可回避的课题,jCifs是一套针对这一N完整而强大的解决Ҏ(gu)Q通过它你可以实现对Q何共享文件系l的讉K?/P>

    一些有用的资源和参考资?/B>

    本文的全部源代码Q可~译q行Q供读者研IӞ下蝲源代?/A>?/P>

    如欲了解更多关于jcifs的信息,误问其官方|站 http://jcifs.samba.org/?/P>

    (zhn)可以在 http://users.erols.com/mballen/jcifs/ 获得jcifs库的最新版本?/P>

    如果你对smbq不是十分熟(zhn),q里有一不错的文章向你介l什么是smbQ?A >http://samba.anu.edu.au/cifs/docs/what-is-smb.html?/P>



    my java 2005-08-19 11:16 发表评论
    ]]>
    Easy Windows Authentication with Tomcat 4.xhttp://www.aygfsteel.com/lmsun/articles/10398.htmlmy javamy javaThu, 18 Aug 2005 03:07:00 GMThttp://www.aygfsteel.com/lmsun/articles/10398.htmlhttp://www.aygfsteel.com/lmsun/comments/10398.htmlhttp://www.aygfsteel.com/lmsun/articles/10398.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10398.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10398.htmlEasy Windows Authentication with Tomcat 4.x Category: Java

    The original blog entry by Robert Rasmussen has disappeared from the Internet (cannot find server) so I'm reproducing it here via Google's caching feature. I've made a few changes to pretty up the formatting, but that's about it.

    I've been pulled into a little internal project, and one of the requirements is that users should be able to authenticate with their Windows login and password. IIS may or may not be in the picture.

    Since the server is a Windows 2000 machine, this turns out to be extremely simple to do thanks to Andy Armstrong's JAAS login modules.

    Once you've downloaded the login modules, set your classpath accordingly and make sure that the directory holding NTSystem.dll is in your %PATH% variable. Next, in the "Sample config" folder you'll find a tagish.login file and a java.security.sample file. The last line in the .sample file is significant, and it needs to be in your $JAVA_HOME/jre/lib/security folder (in a file named java.security). You should copy the tagish.login file there as well. If your users will always be logging into the same domain (which is the case in my situation), just set the defaultDomain property in tagish.login, like this:

    NTLogin
    {
        com.tagish.auth.win32.NTSystemLogin required returnNames=true returnSIDs=false defaultDomain=YOUR_DOMAIN_HERE;
    };
    

    Now, all you need to do to use Windows authentication in your webapps is to make one addition to your server.xml file (or to your specific context's definition):

    <Realm className="org.apache.catalina.realm.JAASRealm" debug="99"
           appName="NTLogin"
           userClassNames="com.tagish.auth.win32.NTPrincipal"
           roleClassNames="com.tagish.auth.win32.NTPrincipal" />
    

    I'll admit this config is slightly hokey. If you look at the Catalina JAASCallbackHandler (which is hardwired to JAASRealm), the way that I have the realm configured above pretty much counts on the User principal (in effect, the user name) being the first principal returned. This is evil, but it works. It would be nice if either Catalina allowed a pluggable CallbackHandler so that I could take advantage of the NTPrincipal.getType() method or if Andy's code returned subclasses of NTPrincipal like UserPrincipal or GroupPrincipal that I could specify in server.xml.

    Once you've got this all configured, the various groups your users belong to equate to role names (so if I belong to an administrators group, my authenticated user will be in role "administrators"), and you can configure security in your webapps using these roles.


    二月 17, 2003 04:11 下午 MST Permalink

    反向跟踪 URL: http://raibledesigns.com/trackback/rd/sunsets/easy_windows_authentication_with_tomcat
    留言:

    Thanks for posting this, Matt.

    ?B minmax_bound="true">{0}发表?Robert Rasmussen on 2003q?2?7? 09:18 下午 MST #

    I have tired this module and used the form authenication in the tomcat. Howerver, it seems cannot login in successfully as it always go into the pages. Please help!!

    ?B minmax_bound="true">{0}发表?Jimmy Wong on 2003q?2?8? 12:42 上午 MST #

    Make sure the path to NTSystem.dll is in your PATH environment variable and that tagishauth.jar is in your $CATALINA_HOME/common/lib. Currently, I believe this only works on a Windows machine. HTH, Matt

    ?B minmax_bound="true">{0}发表?Matt on 2003q?2?8? 07:00 上午 MST #

    If I am running a JVM under an already authenticated NT user, does anyone know how I can easily get the NT domain that the user authenticated to ? Thanks !

    ?B minmax_bound="true">{0}发表?Nicholas Whitehead on 2003q?2?0? 11:59 上午 MST #

    How can I get Subject in my web application with JAASRealm?

    ?B minmax_bound="true">{0}发表?Roman Velichko on 2003q?8?6? 12:21 上午 MDT #

    The same way you always have - request.getRemoteUser()

    ?B minmax_bound="true">{0}发表?Matt Raible on 2003q?8?6? 08:10 上午 MDT #

    This tutorial is out of date...Andy Armstrong updated tagish a few months back...it now has more useful types like NTUserPrincipal and NTGroupPrincipal and a few bug fixes. Also, depending on your requirements, the NTLM functionality added in JDK1.4.2 might help.

    ?B minmax_bound="true">{0}发表?Robert Rasmussen on 2003q?8?6? 10:58 上午 MDT #

    request.getRemoteUser() does return a String not JAAS's Subject.

    ?B minmax_bound="true">{0}发表?Tomasz Luczynski on 2004q?3?9? 03:23 上午 MST #

    [Trackback] This is the solution for my previous post. Samba NTLM Authentication: (Get it here.) This package configures exactly as described. I used the example servlet (NtlmHttpAuthExample) included with the package and set up the filter as in the docs. ...

    ?B minmax_bound="true">{0}发表?Chris Maeda on 2004q?7?8? 10:24 上午 MDT
    站点Q?http://www.cmaeda.com/index.php?p=22 #

    My blog has current info for setting up Tagish 1.03 with Tomcat5.

    ?B minmax_bound="true">{0}发表?Chris Maeda on 2004q?7?8? 10:38 上午 MDT
    站点Q?http://cmaeda.com/index.php?p=22 #

    ?B minmax_bound="true">{0}发表?69.193.88.30 on 2004q?1?9? 03:12 上午 MST
    站点Q?http://www.jenniferconnor.com/ #

    ?B minmax_bound="true">{0}发表?69.193.88.30 on 2004q?1?4? 01:53 上午 MST
    站点Q?http://www.36busty.com/00005602.shtml #

    ?B minmax_bound="true">{0}发表?69.42.81.244 on 2005q?1?1? 02:32 上午 MST
    站点Q?http://www.johnhuron.com/ #

    Hi Matt, Are you still using tagish library with Tomcat 5.x versions?? If yes, could you please point out the final installing directions. With the present blog instructions from Chris Maeda, they doesn't work at all. You can see the problems at http://www.cmaeda.com/index.php?p=22 Please advice. thanks aks

    ?B minmax_bound="true">{0}发表?Vicky on 2005q?4?1? 10:45 上午 MST #

    I prefer not to put my config in $JAVA_HOME/jre/lib/security/java.security instead, use this property when you start tomcat: -Djava.security.auth.login.config=c:/path/to/your/tagish.login

    ?B minmax_bound="true">{0}发表?Joe Scalise on 2005q?8?8? 02:41 下午 MDT
    站点Q?http://www.einvite.com #



    my java 2005-08-18 11:07 发表评论
    ]]>
    Java Authentication and Authorization http://www.aygfsteel.com/lmsun/articles/10366.htmlmy javamy javaWed, 17 Aug 2005 09:38:00 GMThttp://www.aygfsteel.com/lmsun/articles/10366.htmlhttp://www.aygfsteel.com/lmsun/comments/10366.htmlhttp://www.aygfsteel.com/lmsun/articles/10366.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10366.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10366.htmlIntroduction
    This paper explains how to use the Java Authentication and Authorization API (JAAS). It plugs JAAS into the Struts framework. Though this paper focuses on Struts, and in particular the example application distributed with Struts, the lessons learned should be applicable to any MVC web framework.

    In addition, while there are many articles on authentication with JAAS [1], [2] , using the API for authorization is relatively undocumented [3]. This paper will show how to use JAAS to secure resources in an MVC architecture.

    There are two points of integration with Struts. During the login process and when the client requests a resource from Struts (which will usually be a URL). At each of these points, the application should defer to JAAS classes to perform the action.

    This paper will first examine the JAAS infrastructure and then explain how the integration outlined above took place.

     

    Who should read this
    This article is for developers who are relatively familiar with web applications and the java security framework. A sample application in Struts is used for the examples [4], but familiarity with Struts is not required. For information on java security, check out Java Security by Scott Oaks. For information on web applications, check out Sun's web site [5]. For information on Struts, check out the Struts web site [6].

     

    Conventions
    For the purposes of printing, text that should be on one line will be broken up into more. This will be indicated by a backslash (\) at the end of the line.

     

    Authentication
    Login Module
    The login module receives information about the user and authenticates the user, thereby verifying that he or she is a valid subject. There are several implementations of login modules currently available. If a custom login module is needed, resources are available [8].

    Login Module implementations

    Sun provides default implementations for Solaris and NT.


    Tagish has several implementations licensed under the GPL [9].


    JBoss provides several implementations [10].
    Note: For WebLogic 6.1 and Tomcat 3.2, both the jaas.jar and the login module classes needed to be in the non webapp specific classpath.

    These login modules are identified by a name in a configuration file and then called by a LoginContext class that JAAS provides. The LoginContext class does not appear to be thread safe--the javadoc states that " a LoginContext should not be used to authenticate more than one Subject. A separate LoginContext should be used to authenticate each different Subject" [11]. Most of these modules expect to be run from an application or on the command line, and thus to be able to interact directly with a user. Since a web application resides on a server, it may be necessary to write an adapter to pull the needed user information from where the web application stores it and place it in a form that the login module can process.

     

    Module Configuration
    In addition to putting classes that can do authentication in the correct classpath location, some configuration is required to let the JAAS classes know what type of authentication is possible. JAAS allows complex login schemes [12], however, for most web applications, such complexity is not required. Typically, a username and password will be read from a form, and compared against known server side values. An authentication scheme which verifies a username and password combination against a server side file will be examined below.

    Example 1. JAAS login module configuration file

    FileLogin
    {
                com.tagish.auth.FileLogin required debug=true \
                pwdFile="/usr/local/tomcat/webapps/struts-example/WEB-INF/passwd";
    };

    In Example 1, the FileLogin authentication scheme has one required module. FileLogin implemented by the com.tagish.auth.FileLogin class. Both the class name and a token indicating the relationship of the module to the scheme are mandatory. Here the required token indicates that the FileLogin module must validate this login or the scheme as a whole fails. It is also possible to pass additional information to the login module in this configuration file. This module needs to know where its password file is located.

    Since this configuration file may be located anywhere on the file system, the authentication classes need to be informed where this file is. There are two ways to do this: adding parameters to a JVM wide general configuration file (java.security), or passing the information in on the command line when starting the JVM.

     

    Setting Login Configuration Information Via java.security
    This file is where the JVM looks for security related configuration parameters. It is typically located in the JAVA_HOME/jre/lib/security directory. It is possible to have an arbitrary number of login configuration files detailing any number of authentication schemes. These are "read and unioned into one single configuration" [13].

    Example 2. java.security entry for login module configuration

    login.config.url.1=file:${java.home}/lib/security/tagish.login
    login.config.url.2=file:${java.home}/lib/security/struts.login

    This entry specifies the location of files containing authentication scheme definitions. Also, note that java system properties may be referenced in java.security.

    If the second line looked like login.config.url.3=file:${java.home}/lib/security/struts.login (note the 3), then struts.login would not be searched for login modules. Scanning begins at login.config.url.1 and continues to increment the suffix until no file is found. This is an implementation detail of the default Sun provided authentication classes. For more information, read about the Login Configuration Provider [14].

     

    Setting Login Configuration Via the Command Line
    It is also possible to set a java property on the command line when starting the JVM that tells it where to look for the JAAS login scheme configuration file. The property name is java.security.auth.login.config.

    Example 3. Setting the location of the login scheme configuration file on the command line

    $ java ... \
    -Djava.security.auth.login.config==$JAVA_HOME/jre/lib/security/tagish.login ...

    This command line overrides any previously set value for the login scheme configuration file location. In typical java fashion, if there was just one = in Example 3, an additional location for the login scheme configuration file would be specified.

     

    Integrating Authentication Into Struts
    After the login module is recognized by JAAS, hooks into the web application need to be written. In the example application, an Action class takes a username and password from its Form class and authenticates the user against a database. This is the logical place to hook in the JAAS authentication module.

    The Struts example application has a LogonAction class. Initially, the relevant portion of this class looks like this (note that this code is unchanged except to break up lines for ease of printing).

    Example 4. Initial LogonAction Authentication

       125          String username = ((LogonForm) form).getUsername();
       126          String password = ((LogonForm) form).getPassword();
       127          Hashtable database = (Hashtable)
       128            servlet.getServletContext().getAttribute( \
                            Constants.DATABASE_KEY \
                            );
       129          if (database == null)
       130              errors.add(ActionErrors.GLOBAL_ERROR,
       131                         new ActionError("error.database.missing"));
       132          else {
       133              user = (User) database.get(username);
       134              if ((user != null) && !user.getPassword().equals(password))
       135                  user = null;
       136              if (user == null)
       137                  errors.add(ActionErrors.GLOBAL_ERROR,
       138                             new ActionError("error.password.mismatch"));
       139          }


    On line 125 and 126, the username and password that were submitted on the form are extracted into local variables. The code looks for an authentication database and verifies its existence on lines 127-132. Line 134 is where the actual authentication occurs. If the user exists in the database and the password in the database is the same as the password entered on the form, then the user is authenticated.

    This approach works just fine for a sample application. The LogonAction class does all of the authentication in the perform method. But the LogonAction class should be a thin layer deferring the actual work to business objects. In addition, switching the source users are authenticated against requires changes to this class since it is hard coded to expect a password and username. Also, as mentioned in the "Login Module" section, using the JAAS authentication module will be difficult, as most implementations expect some level of user interaction. Putting a business object between the Struts application classes and the JAAS classes can make life easier.

    Example 5. Modified LogonAction Authentication

      125          String username = ((LogonForm) form).getUsername();
       126          String password = ((LogonForm) form).getPassword();
       127          Hashtable database = (Hashtable)
       128            servlet.getServletContext().getAttribute(Constants.DATABASE_KEY)
       129          if (database == null)
       130              errors.add(ActionErrors.GLOBAL_ERROR,
       131                         new ActionError("error.database.missing"));
       132          else {
       133              Auth fa = new com.xor.auth.FileAuth(username,password);
       134              if (fa.authenticate()) {
       135                  user = (User) database.get(username);
       136                  HttpSession sess = request.getSession();
       137                  sess.setAttribute(Auth.SUBJECT_SESSION_KEY, fa.getSubject());
       138              }

    Lines 125-132 are the same in this example as they were in Example 4. However, rather than the LogonAction class performing the authentication, it defers to a special Auth class. Note that on line 135, the database is still used to get the User object, since the sample application used it in other code.

    Auth is a custom interface specifying the contract that the adapter for the JAAS classes must fulfill to interface with web applications in general and this example application in particular. FileAuth is an implementation of that interface which adapts the com.tagish.auth.FileLogin login module specified in Example 1.

     

    Calling the Tagish Authentication Module
    The FileAuth class defers to the FileLogin class for almost all its functionality.

    Example 6. The authenticate Method of the FileAuth Class

         1     public boolean authenticate() {
         2         try {
         3             lc = new LoginContext("FileLogin", \
                            new MyCallBackHandler(username,password));
         4             lc.login();
         5         } catch (LoginException le) {
         6             return false;
         7         }
         8         return true;
         9     }

    On line 3, the LoginContext object is told to look for the FileLogin authentication scheme, and passed a custom callback handler. Normally, callback handlers interact with the user and retrieve information needed for authentication, but the ActionForm class has already done this. In a way, the form is a "call forward" handler, because the request/response paradigm of the web does not fit well with the client/server architecture of which the callback handler is part. The problem is worked around by passing the needed information to the callback handler on instantiation.

    On line 4, the LoginContext attempts to login the user via the modules found in the FileLogin authentication scheme. If the login fails for any reason, a LoginException will be thrown, otherwise flow continues normally. A Subject is instantiated by the login module and exposed as a property of the LoginContext object. The Subject is also populated with the Principals associated with that user by the login module.

     

    Cache Subject in Session
    After successfully authenticating the user, the Subject should be stored in the HttpSession. (The Subject is small; one Subject with one Principal serialized to a file 337 bytes in size.) This caching allows other parts of the application to perform authorization checks without requiring the user to login again. It also ensures that the other parts of the application are aware that the user has been authenticated, and logs out the user when the HttpSession expires. The storage process is shown on line 137 of Example 5; here the portion of the API of the login module that returns the newly authenticated Subject is examined. To retrieve the subject, the FileAuth class again defers to the LoginContext.

    Example 7. The FileAuth Class Exposes the Subject

         1     public Subject getSubject() {
         2         if (lc == null) {
         3             throw new IllegalStateException("either login failed or \
                    the authenticate method hasn't been called.");
         5         } else {
         6             return lc.getSubject();
         7         }
         8     }

    The getSubject method can only be called after the authenticate method.

    Of course, another option would be to store the username and password in the session, and re-authenticate every time. If the Subject were large and the authentication process was fairly fast, this option might be viable.

     

    Authorization
    Permissions
    Permissions are the heart of authorization; they control access to resources. However, the JAAS permissions are built on top of the existing java security model. This model is very good for controlling access to resources like sockets and files, but has no concept of URLs. Thus, to apply JAAS to a web application, a new permission class must be created.

     

    Create permission class
    A custom Permission class that understands URLs must be created. There are two ways to do this.

    Extending java.security.BasicPermission is one option. Using this would tie permissions to literal URLs (e.g, one could say that the admin principal should have access to the /admin/index.do page). However, the other option would be better: to create a URLPermission class extended the java.security.Permission class and handled wild cards in a manner similar to the java.io.FilePermission class [15]. Then, one could say that the admin principal should have access to the /admin/ directory and all resources below it.

    In either case, since URLs are read only, there is no need for any of these permissions to have an action attribute. On the other hand, it may be useful to specify an attribute of a Permission to determine whether a given URL may only be viewed over a secure connection. For more on extending Permissions in novel manners, see the interesting IBM article titled Extend JAAS for class instance-level authorization [16].

    However, since this is a proof of concept, a BasicPermission implementation is fine. For a production system, subclassing Permission would be required.

     

    Access Control Policy Configuration Files
    The default configuration for JAAS permissions looks much like the configuration for normal java security. Java security entries consist of a listing of permissions. The permissions can be limited to either a specific code base, or code that has been signed by a specific person, or both. JAAS permission listings can have none, one or both of these elements. However, at least one Principal association is required.

    Example 8. Sample JAAS policy file


    grant  Principal * * {
      permission com.xor.auth.perm.URLPermission \
      "/struts-example/logoff.do";
    };

    grant  Principal com.tagish.auth.TypedPrincipal "user" {
      permission com.xor.auth.perm.URLPermission \
      "/struts-example/editRegistration.do";
    };

    grant  Principal com.tagish.auth.TypedPrincipal "admin" {
      permission com.xor.auth.perm.URLPermission \
      "/struts-example/editRegistration.do";
      permission com.xor.auth.perm.URLPermission \
      "/struts-example/adminMenu.do";
    };


    The first grant allows everyone to view the logoff.do resource. Anyone with the user Principal is allowed to view /struts-example/editRegistration.do.

    At times there will be principals that are granted a superset of the permissions granted to other principals. For example, in Example 8, subjects with the admin principal can view all resources that subject with the user principal can. However, the /struts-example/editRegistration.do URL is listed twice (once in the user section and once in the admin section). It would be nice to be able to avoid duplicating permissions and delineating this relationship between principals, but this is not possible. While more than one principal can be listed for a given set of permissions, if that happens, "[t]he current Subject running the code must have all of the specified Principals in its Principal set to be granted the entry's Permissions" [17]. However, this problem may be dealt with by granting all users with the admin Principal the user Principal as well.

    On the other hand, it is possible to have permissions be supersets of other permissions. The implies method of the Permission class can be overridden to provide this behavior. For example, there could be an admin Permission which could imply all other URL permissions.

    Note: Example 8 is an example of a file based implementation of the policy. It canbe replaced with a RDBMS implementation by changing the value of the auth.policy.provider variable in the java.security file.
    Since the policy file may be located anywhere, JAAS needs to be told where to look for it (this problem is similar to that faced by the authentication configuration setup detailed in Section 2.2. There are two ways to do this: adding parameters to a system wide general configuration file (java.security), or passing the information in as a command line option when starting the JVM.


    Note: With WebLogic 6.1, only the command line method worked. Tomcat 3.2 seemed to work with both methods.


    Setting the JAAS Policy File Location in the java.security file
    This file is where the JVM looks for security related configuration parameters. It is typically located in the JAVA_HOME/jre/lib/security directory. It is possible to have arbitrary numbers of JAAS policy files. These are "read and unioned into one single policy" [18].

    Example 9. java.security entry for permission policy configuration

    auth.policy.url.1=file:${java.home}/lib/security/struts.policy
    auth.policy.url.2=file:${user.home}/.struts.policy

    This example should check the policy files in both places. Note also that java system properties can be referenced in the java.security file.

    If the second line looked like auth.policy.url.3=file:${user.home}/.struts.policy (note the 3), then the .struts.policy file would not be searched for permission sets. Scanning starts at auth.policy.url.1 and increments the suffix by one until there is no file found. This is an implementation detail of the default Sun permission file parsing class. Obviously, an authorization scheme that used a database would have different behavior.

     

    Setting the JAAS Policy File Location Via the Command Line
    It is also possible to set a java property on the command line when starting the JVM that tells it where to look for the JAAS policy file. The property name is java.security.auth.policy.

    Example 10. Setting the location of the JAAS policy file on the command line

    $ java ... \
    -Djava.security.auth.policy==$JAVA_HOME/jre/lib/security/struts.policy ...

    This command line overrides any previously set location of the JAAS policy file. If there was only one =, the property would indicate an additional policy file path.

     

    Integrating Authorization into Struts
    Now that permissions have been set up and JAAS knows about them, it is time to actually apply them in the context of the application. Every java class that accesses a potentially security sensitive resource needs to check to see if the SecurityManager is running, and if so verify that the calling class is running in a context that allows the access.

    Example 11. Typical permission check

    Permission p = new FilePermission("/tmp/foo","read");
    SecurityManager s = System.getSecurityManager();
    if ( s != null) s.checkPermission(p);

    The code here is trying to read /tmp/foo. If no SecurityManager is installed (typically via the -Djava.security.manager command line switch), System.getSecurityManager() returns null, and access does not need to be verified.

    The web application needs to perform a similar check for each URL that the user is trying to view. In an MVC architecture, the logical place to put such access control is the controller. In Struts, the ActionServlet is the controller. For the sample application the controller class, org.apache.struts.action.ActionServlet, was subclassed, and the process method was overridden.

     

    Installing Access Control Logic into the ActionServlet
    First of all, it is important to note that when the ActionServlet is subclassed to provide authorization services, only resources that the ActionServlet controls are protected. Thus, in the example application, only Actions are protected. In a real application, it'd be better to have two methods of access control:

    A central servlet which checks authorization before any URL is viewed. For example, all users may need to be logged in before viewing any pages. (If using the 1.3 version of the servlet specification, a filter might be a good choice.)


    A JSP tag or other method which may be used to check to see if a user has a given principal before showing content fragments. For example, a menu item may only be accessible to users with the admin permission.
    Both of these should delegate to a business class that does the actual security check.

    There are at least two pages whose view should not be protected at all: the login page and the login error page. In addition, there are certain security attributes that are peculiar to web applications; for example, some users may need to have all interaction over an SSL connection. The controller needs to do at least three things to provide authorization services for a web application.

    Recognize which pages are viewable by every authenticated user and respond accordingly.


    Recognize which state, secure or non secure, a request is in and respond accordingly.


    Check to see that a user is allowed to view a given URL and respond accordingly.


    The ActionServlet Subclass
    Example 12. The Overridden process Method


         1    protected void process(HttpServletRequest request, \
                HttpServletResponse response)
         2    throws ServletException, java.io.IOException
         3    {
         4        String loginPage = request.getContextPath()+"/logon.do";
         5        String pageReq = request.getRequestURI();
         6        Permission perm = \
                    PermissionFactory.getInstance().getPermission(pageReq);
         7        Subject subject = \
                    ((Subject)(request.getSession().getAttribute( \
                        Auth.SUBJECT_SESSION_KEY)));
         8        if (subject == null && \
                    (! request.getRequestURI().equals(loginPage))) {
         9            // redirect to login page
        10        } else if (subject == null &&  \
                    request.getRequestURI().equals(loginPage)) {
        11            // login page is always permitted
        12             super.process(request,response);
        13
        14        } else {
        15              if ( ! AuthUtils.permitted(subject, perm) ) {
        16              // subject is not permitted; redirect to error page
        17       } else {
        18                 super.process(request,response);
        19             }
        20         }
        21    }


    Lines 6 and 7 get needed information including the Permission that represents the URL the user is trying to access (PermissionFactory is a factory class that returns the appropriate Permission), and the cached Subject.

    On lines 8-14, the case of the unauthenticated user is handled by redirecting the user to the login page, where access is always allowed (line 12). The reason that this can't be handled by the wildcard grant in Example 8 is that the Subject is null in this case. If the program catches this and creates a new Subject, that Subject still has no Principals and thus is still denied access. For a production system, it's conceivable this case could be handled with an anonymous Principal.

    If this is a request for any other resource than the login page, on line 15 the access control class is called. Access is either disallowed, or the process method of the superclass is called.

    The ActionServlet should not know about the particulars of the access control; this should instead be handled by a business class. For this example, such a business class was written; it is examined in the next section.

     

    The Access Control Class
    This class is similar to the java.security.AccessController class [19], and ends defers to that class eventually (via the SecurityManager). The logic in the class can then be reused anywhere that authorization is needed. The class will basically check whether a Subject has a given Permission.

    Example 13. An Abridged Permission Checking Class

         1 package com.xor.auth;
         2
         3 import java.security.*;
         4 import javax.security.auth.*;
         5 import java.util.*;
         6
         7 public class AuthUtils {
         8
         9     static public boolean permitted(Subject subj, final Permission p) {
        10         final SecurityManager sm;
        11         if (System.getSecurityManager() == null) {
        12             sm = new SecurityManager();
        13         } else {
        14             sm = System.getSecurityManager();
        15         }
        16         try {
        17             Subject.doAsPrivileged(subj, new PrivilegedExceptionAction() {
        18                 public Object run() {
        19                     sm.checkPermission(p);
        20                     return null;
        21                 }
        22                 },null);
        23             return true;
        24         } catch (AccessControlException ace) {
        25             return false;
        26         } catch (PrivilegedActionException pae) {
        27             return false;
        28         }
        29     }
        30 }

    The example has had all logging, error checking and comments removed for brevity. Production code should, for example, test to see that neither the Permission nor the Subject are null.

    Lines 10-15 create a SecurityManager. If the application happens to be one of the rare java applications that run with a SecurityManager installed, then that SecurityManager should be used. If not, a new one is created to check the permissions on line 12.

    Lines 16-23 do the actual permission check. If the Subject does not have a Principal which has been granted the Permission, the SecurityManager will throw an exception. For reasons of cleanliness and clarity, this exception is caught and converted to false, which is returned to the calling class. Otherwise, the action is allowed, and true is returned.

    The null on line 22 is very important; it tells the SecurityManager to consider this resource access in an isolated context, ignoring the permissions of code currently on the execution stack. For further information, see chapter 5 of Java Security.

    Note: If the application is running with a SecurityManager enabled, make certain that the AuthUtils class has been granted the doAsPrivileged AuthPermission in the standard java security policy file. Otherwise, this permission checker will not be able to run; a SecurityException will be thrown when line 17 is reached.


    Conclusion
    The authentication piece of JAAS seems fairly bulletproof. The idea of pluggable authentication modules is great and the developer can leverage a number of existing modules to ease development.

    Using JAAS to leverage the SecurityManager for authorization is entirely commensurate with the java security model. There are resources that only certain users with certain principals should be able to see. Rather than reinvent an access control layer, it makes sense to use the one that java already provides.

    However, there are some caveats. This was an extremely simplistic example, and the reader will have noted the number of places where parts of the system need to be replaced to create a production system; these include a new controller, permission class, and policy implementation. In addition, this permission model does not map well to the concept of different protocols used to view a URL.

     


    Definitions
    user: a real world entity. It can be another computer system or a human being. This is not represented by an object.


    subject: the user as seen by the web application. Subject is the class that represents this concept.


    principal: one view of the subject. The API states that it "represents the abstract notion of a principal, which can be used to represent any entity, such as an individual, a corporation, and a login id A Principal is a class that represents a principal" [7]. A principal can be thought of as a role or a group, but those terms have special meaning in J2EE (in the servlet container, for one).


    resource: anything in a system to which unlimited access is not granted to all.


    permission: access to a resource. The Permission class represents a triplet of resource, action and name. Permissions can be granted to a Principal.


    Authentication: the act of verifying that a user is a subject and granting the user certain principals; "who you are."


    Authorization: the act of verifying that a user is allowed to access a certain resource; "what you may do."


    Authentication module: one method of authenticating a user. Examples include verifying against /etc/passwd and examining the contents of a cookie.


    Authentication scheme: a combination of authentication modules.



    my java 2005-08-17 17:38 发表评论
    ]]>
    Authenticate a Servlet App using Windows Passwords?http://www.aygfsteel.com/lmsun/articles/10362.htmlmy javamy javaWed, 17 Aug 2005 09:28:00 GMThttp://www.aygfsteel.com/lmsun/articles/10362.htmlhttp://www.aygfsteel.com/lmsun/comments/10362.htmlhttp://www.aygfsteel.com/lmsun/articles/10362.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10362.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10362.html

    Current instructions for configuring Tomcat for JAAS-based Windows authentication.
    This is the solution for my previous post.

    Samba NTLM Authentication: (Get it here.) This package configures exactly as described. I used the example servlet (NtlmHttpAuthExample) included with the package and set up the filter as in the docs. The web.xml file is here.

    Notes: I tested on my home (windows) network which does not have a domain controller; I used workgroup authentication and did not test against a PDC. So YMMV.

    There are two main drawbacks of this approach:

    The first is that the jcifs filter (as currently implemented) does not return group membership information. If your servlet app uses security roles and security constraints, this is a problem since you need some way of getting a user’s group memberships (so the container can map them to security roles). You could get probably around this problem by extending the jcifs library to return group information; this is more work than I planned to invest. Another approach would be to create a second filter that maps user names to group memberships, perhaps using the tomcat-users.xml file. This would be cumbersome and proprietary, but it would probably work.

    The second drawback is that NTLM authentication is deprecated in the Windows world. Windows 2000 and 2003 use Kerberos authentication, and only fall back on NTLM when they have to.

    For these reasons, I abandoned the Samba NTLM approach and looked at the Tagish / JAAS approach.

    JAAS with Tagish SSPI JAAS provider: JAAS with the Tagish SSPI-based login module is the way to go. The Tagish login module is based on the Windows SSPI API, which provides an authentication service for distributed environments using the best available protocol; i.e. it uses Kerberos when that is available and transparently falls back on NTLM when Kerbos is not available. In addition, SSPI returns the group membership information, which is necessary for servlet apps that use security roles and security constraints.

    The first step in setting this up is to configure the Tagish login module according to the instructions that come with it. In a nutshell, the steps are as follows:

    • Put NTSystem.dll somewhere on your path
    • Put tagishauth.jar on your classpath
    • Copy the tagish.login file to $JAVA_HOME/jre/lib/security
    • Add this line:
      login.config.url.1=file:${java.home}/lib/security/tagish.login
      to your java.security file (in $JAVA_HOME/jre/lib/security)

    You can test the configuration using the login.bat file that comes with the Tagish package. If you are on a workgroup, you may need to edit a registry setting to get network authentication to work properly. (I had to.) See this Microsoft KB article for more information; apparently, Windows XP has a “ForceGuest?parameter that forces all network logins for a workgroup to use the guest account.

    The second step is to configure Tomcat to use this login module. Here are the steps I used to configure it in Tomcat 5.0.16. Note that the first 4 steps are the same ones for setting up the Tagish login module, just tweaked a little for Tomcat.

    • Copy NTSystem.dll to the Tomcat5 bin directory
    • Copy tagishauth.jar to the Tomcat5 common/lib directory
    • Copy tagish.login to the $JAVA_HOME/jre/lib/security directory. I set the defaultDomain parameter to the name of my server since I’m on a workgroup.
    • Add this line:
      login.config.url.1=file:${java.home}/lib/security/tagish.login
      to your java.security file (in $JAVA_HOME/jre/lib/security)
    • Configure a JAAS Realm in your Tomcat server.xml file using the following element:
      <Realm className=”org.apache.catalina.realm.JAASRealm?debug=?0?BR>   appName=”NTLogin?BR>   userClassNames=”com.tagish.auth.win32.typed.NTUserPrincipal?BR>   roleClassNames=”com.tagish.auth.win32.typed.NTGroupPrincipal?/>

    The most important thing to remember is that the userClassNames and roleClassNames have to be exactly the same names as the classes that the Tagish login module returns. This is necessary because the Tomcat JAASRealm class compares the classnames of the principal objects with the class names given in the realm configuration. If they do not match exactly, they are ignored.

    You can test the configuration using the same NtlmHttpAuthExample servlet that we used to test Samba NTLM. You need a different web.xml that uses security roles; the one I used is here. For this to work, you have to login using an account that is a member of the TESTGROUP group.

    To debug it, I had to get log4j working with Tomcat5, which is an adventure in itself. It turns out that the instructions in the Tomcat5 FAQ are incomplete; you need to add commons-logging.jar to common/lib in addition to all the other steps. If you run into trouble, getting log4j debug messages out of the org.apache.catalina.realm package should tell you what is going wrong.

    16 Responses to “How To Authenticate a Servlet App with Windows Passwords?/H3>
    1. carmen Says:

      hi,
      I cannot get tagish working! I don’t know what I’m doing wrong. Someone can help me please? I’ve followed the list above step by step :(
      System: Struts and tomcat on W2000 professional (but also tried same config on W2000 server and it doesn’t work either)
      Thanks

      stack trace:

      19-Jul-2004 17:17:12 org.apache.catalina.realm.JAASRealm authenticate
      WARNING: Login exception authenticating username Administrator
      javax.security.auth.login.LoginException: Error: javax.security.auth.callback.TextInputCallback@da3772 not available to garner authentication information from the user
      at com.tagish.auth.win32.NTSystemLogin.login(NTSystemLogin.java:128)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:324)
      at javax.security.auth.login.LoginContext.invoke(LoginContext.java:675)
      at javax.security.auth.login.LoginContext.access$000(LoginContext.java:129)
      at javax.security.auth.login.LoginContext$4.run(LoginContext.java:610)
      at java.security.AccessController.doPrivileged(Native Method)
      at javax.security.auth.login.LoginContext.invokeModule(LoginContext.java:607)
      at javax.security.auth.login.LoginContext.login(LoginContext.java:534)
      at org.apache.catalina.realm.JAASRealm.authenticate(JAASRealm.java:281)
      at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:129)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
      at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
      at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
      at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
      at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
      at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
      at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
      at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
      at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:793)
      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:702)
      at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:571)
      at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:644)
      at java.lang.Thread.run(Thread.java:534)
      19-Jul-2004 17:20:17 org.apache.coyote.http11.Http11Protocol pause
      INFO: Pausing Coyote HTTP/1.1 on http-8080

    2. Chris Maeda Says:

      I saw this problem; it was caused by a mistake in the config files. Does Tomcat throw an earlier exception that complains about parsing the tagish login config file? If the parse fails, the callback handler will not be initialized.

    3. Manju Panjwani Says:

      I am also facing the same issue.
      WARNING: Login exception authenticating username Administrator
      javax.security.auth.login.LoginException: Error: javax.security.auth.callback.TextInputCallback@da3772 not available to garner authentication information from the user
      at com.tagish.auth.win32.NTSystemLogin.login(NTSystemLogin.java:128)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

      Were you able to resolve the above? Please guide.

    4. Louis A Johannson Says:

      I’ve got the Tagish example working fine where I can use the batch login.bat to test a

      login/authentication. I can also integrate it with JAAS security and have it authenticate me

      against my network in a console application. However, as soon as I try to tie it into

      Tomcat, I get stuck. (I’m trying an web-app example based on BASIC authentication)

      I think my files are in the correct places (I get different errors when they’re missing) and

      I can make my tomcat example web-app work using a different authentication method (the

      tomcat manager’s memory-realm user authentication works fine) and I’ve even done the JAAS

      example to replace the security realm of the tomcat manager app with JAAS.

      The problem I’m getting now is that I get a serious bomb that kills tomcat as soon as I try

      to access the protected directory:

      An unexpected exception has been detected in native code outside the VM.
      Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at PC=0x7BF6256
      Function=[Unknown.]
      Library=C:\Projects\workspace3\example.Tomcat_NT\lib\NTSystem.dll

      NOTE: We are unable to locate the function name symbol for the error
      just occurred. Please refer to release documentation for possible
      reason and solutions.

      Current Java thread:
      at com.tagish.auth.win32.NTSystem.logon(Native Method)
      - locked <0x10024d98> (a com.tagish.auth.win32.NTSystem)
      at com.tagish.auth.win32.NTSystemLogin.login(NTSystemLogin.java:134)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      ...

      I’m really rather at a loss as to why this is happening. It ‘feels?like there is something

      wrong with the tagish module, but if others got it working I really don’t know. Did you have

      to extend it at all? Or wrap it up in an implemented JAAS interface? (but tagish has done

      that already haven’t they?)

      Config:
      Tomcat 5.0.27/28
      Eclipse 3.0
      Sysdeo eclipse/tomcat plugin
      J2SDK 1.4.2_05
      Tagish 1.0.3

      I also tried plugging the tagish module straight into a clean tomcat (without using any of

      my code) to replace the security realm of the manager web-app. The error is slightly

      different here:

      7-Sep-2004 12:46:17 AM org.apache.catalina.realm.JAASRealm authenticate
      WARNING: Login exception authenticating username louis
      javax.security.auth.login.LoginException: Error: javax.security.auth.callback.Te
      xtInputCallback@354749 not available to garner authentication information from t
      he user
      at com.tagish.auth.win32.NTSystemLogin.login(NTSystemLogin.java:128)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
      java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
      sorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:324)
      at javax.security.auth.login.LoginContext.invoke(LoginContext.java:675)
      at javax.security.auth.login.LoginContext.access$000(LoginContext.java:1
      29)
      at javax.security.auth.login.LoginContext$4.run(LoginContext.java:610)
      at java.security.AccessController.doPrivileged(Native Method)
      at javax.security.auth.login.LoginContext.invokeModule(LoginContext.java
      :607)
      at javax.security.auth.login.LoginContext.login(LoginContext.java:534)
      at org.apache.catalina.realm.JAASRealm.authenticate(JAASRealm.java:316)
      at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(Bas
      icAuthenticator.java:129)

      Does anyone have a clean working example in tomcat they’d be willing to zipup and post?

      My proper email prefix is: louis_a_j
      Suffix: telus.net

    5. Louis A. Johannson Says:

      P.S. As per the following post:
      Tagish and JBOSS
      I’ve tried substituting a default domain into the tagish.login (my workgroup) but that just brought me back to the previous exception which kills tomcat.
      Note: I’ve tried this on both an NT4 domain and on a windows 2000 workgroup with the same results in both.

    6. Louis Johannson Says:

      Sorry, the link I included broke:
      http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3837312#3837312

    7. Aaron Hawkins Says:

      I have the same problem as the #4 comment on this page submited by Louis Johannson. I can authenticate using a console app, but when I try and follow the instructions to authenticate agains Tomcat, my jvm blows up with the same error. It seems that there is a problem with NTSystem.dll. If it is anywhere on my path, my jvm will blow up when I try and use tomcat. If I delete it, then I get errors about it not being found. Has anyone found a solution to this? Any help would be appreciated.

    8. Aaron Hawkins Says:

      I have found the solution to the problem described by post #4. The NTSystem.dll doesn’t appear to like a null username. When trying to get this to work with Tomcat, if you use Form based authentication, you can avoid sending a null username, and everything works great.

    9. rafal piotrowski Says:

      Hi
      I try to use samba ntlm filter first and I’ve got some problem.
      If I try to open some web page from my web app the internet browser logon dialog always shows.
      How should I configure my Windows XP workstation to eliminate this dialog.

    10. mgr Says:

      Hi,
      I have a question about automatic authentication.

      I have a windows 2003 server with active directory. Tomcats and JAAS libraries are correctly installed and configured. When I try to access to the web site I protected by the realm, a login/password is requiered, and I can access to the web site after authentication.

      My question is: is it possible not to have the login/password dialog box if I access to Web site with a computer that belongs to the domain I create and if i’m logged with the correct login/password to have access.
      I would automatically enter to the web site as I’m already authenticated in the Windows session. Is that possible?

      The case is the same if I try locally, on the server. I’m logged with an account who belongs to the domain, and this account belongs to the group I defined in the active directory and in the web.xml file of the web site. But the system ask me the login/password and don’t acces directly to the web site.

      Thanks

    11. Mel Riffe Says:

      I’m starting down this path also and having some troubles. One thing I noticed there is a typo in the instructions. I think you should update the java.security file like so:
      login.config.url.1=file:${java.home}/jre/lib/security/tagish.login

      Plus I added the following to Tagish’s login.bat:
      -Djava.security.auth.login.config=C:\j2sdk1.4.2_06\jre\lib\security\tagish.login

      Next step…authenticating in Tomcat?/P>

      - Mel

    12. Trinition Says:

      I modified the NTSystemLogin source in the Tagish JAAS module to throw a FailedLoginException for a null username or password,a nd not normal BASIC auth works. I presume the null was blowing up in the Tagish NTSYstem.dll or the call it makes to the Win32 API. I shared my update with the Tagish JAAS author, so I’ll see what he thinks.

    13. vicky Says:

      Hi, I am trying to use tagish with tomcat 5.0.27 and exactly getting all the same problems mentioned by others. Is there any clear way to use tagish??

      Please advice.
      thanks
      aks

    14. jh Says:

      does this also work on websphere server?

    15. Kris Dover Says:

      Aaron Hawkins, thanks a million. My tomcat 5.0.28 was also crashing with the Basic authentication and i noticed the username null entries in the stdout.log and wondered if that was causing it, but never made an attempt to resolve it using form base authentication until reading your message. seemed very unusual that tomcat’s basic authentication was returning nulls even when the correct username and password were entered on the first try. go figure. Trinition, i haven’t seen an update with your recommended fix, so i might just hack the java code myself. thanks.

    16. Joe Says:

      The TextInputCallback is issued when you do not have a defaultdomain=”yourdomain?in your tagish.login file, there is no way for a TextInputCallback to work through the servlet, the source should be changed so that it could parse the domain from the username callback if no default domain is specified, however some people may want to have a text callback for applications instead of servlets.

      The Null username does indeed crash the NTSystem.dll, simply change the login attempt:

      succeeded = false
      ntSystem.logon(username, password, domain); // may throw
      succeeded = true;

      to:

      succeeded = false;
      if (username == null || password == null) {
      throw new LoginException("Error: " + username == null ? "username" : "password" + ", null, not allowed");
      }
      ntSystem.logon(username, password, domain); // may throw
      succeeded = true;

      and recompile the tagish src to a jar file, deploying it in the Tomcat/bin directory like explained above and everything will work correctly even with Basic auth.

      This is great and all, but I don’t see how tagish is using NTLM, unless you mean it is talking to my domain to get my roles using kerberos or NTLM, it does not however provide the transparent login that jCIFS does. I looked throught the tagish source and don’t see anything in there either, did I misread your article or did I overlook something?



    my java 2005-08-17 17:28 发表评论
    ]]>Tagish.net JAAS LoginModuleshttp://www.aygfsteel.com/lmsun/articles/10344.htmlmy javamy javaWed, 17 Aug 2005 07:48:00 GMThttp://www.aygfsteel.com/lmsun/articles/10344.htmlhttp://www.aygfsteel.com/lmsun/comments/10344.htmlhttp://www.aygfsteel.com/lmsun/articles/10344.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10344.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10344.html

    q期先介l有?Authentication 的部? JAAS 提供?PAM ( Pluggable Authentication Module ) 的模? ?以通过标准?API 建立属于自己?LoginModule, Ҏ(gu) stackable 原理, q而相关相关的w䆾验证E序, 辑ֈ SSO ( Single Sign-On ) ?目的.


    SECTION 02 JAAS 中几个比较常见的 classes

    本节详细解说请参?http://java.sun.com/j2se/1.4.2/docs/guide/security/jaas/JAASRefGuide.html


    普通对?
    • Subject
    • Principals
    • Credentials
    w䆾验证相关的对?
    • LoginContext
    • LoginModule
    • CallbackHandler
    • Callback
    权限控相关的对?
    • Policy
    • AuthPermission
    • PrivateCredentialPermission

    SECTION 03 Tagish.net ?LoginModules

    现在地点 http://free.tagish.net/jaas/


    最新版?1.0.3


    目前 tagish.net 提供了几U?LoginModules, 包含了?
    • com.tagish.auth.DBLogin
    • com.tagish.auth.FileLogin
    • com.tagish.auth.win32.NTSystemLogin
    一般h大多比较熟?zhn)数据库操? 首先先徏立一?login.config, 內容?
    JAASLogin
    {
    	com.tagish.auth.DBLogin required 
    	dbDriver="sun.jdbc.odbc.JdbcOdbcDriver" dbURL="jdbc:odbc:DBLogin";
    };
    
    ?Principal 讄?com.tagish.auth.TypedPrincipal ( 如果?NTSystemLogin 则设|ؓ com.tagish.auth.win32.NTPrincipal ). 接着, 你的数据库需要一些表,

    分别在数据库內设|完? 当你启动你的E序的时? 你需要在 classpath 中设|相关的 JDBC Driver, ?SecurityManager 参?login.config, 去调?DBLogin api, 取得合法或不合法的状?


    SECTION 04 关于 PAM stack

        Login2 {
           sample.SampleLoginModule required;
           com.sun.security.auth.module.NTLoginModule sufficient;
           com.foo.SmartCard requisite debug=true;
           com.foo.Kerberos optional debug=true;
        };
    
    假如我们?Login2 的这U登陆stack, 可以讄 required, sufficient, requisite, optional 四种状?
    • required : 验证必须成功, 但是不论成功或失败都l箋执行下面的登陆模? 执行所有之后才丟出验证p|.
    • requisite : 验证必须成功, 但是p|马上回M做其他验? 必须成功才l执行下面的登陆模块.
    • sufficient : 验证可以不要成功, 但是成功了就马上回去不做其他验证, p|可以l箋执行其他的登陆模?
    • optional : 验证可以不要成功, 但是不论成功或失败都l箋执行下面的登陆模?
    所? Login2 的登? 首先我们会先使用 sample.SampleLoginModule 来验?

    不论成功或失败都会执?com.sun.security.auth.module.NTLoginModule,

    如果 NTLoginModule 验证成功, 因ؓ?sufficient, pȝp定这个h是合法的使用?

    ?NTLoginModule 验证p|, ׃q行 com.foo.SmartCard 的验?

    如果 SmartCard 验证p|, q接宣告你不是合法的用?

    如果 SmartCard 验证成功, ql到 Kerberos 的验证模?

    因ؓ Kerberos 是属?optional, 所以根本对w䆾验证的结果没有媄?

    Login2 验证的各U状况列?/B>
    SampleLoginModule required pass pass pass pass fail fail fail fail
    NTLoginModule sufficient pass fail fail fail pass fail fail fail
    SmartCard requisite * pass pass fail * pass pass fail
    Kerberos optional * pass fail * * pass fail *
    Overall Authentication pass pass pass fail fail fail fail fail
    * = 不会被执? 直接回应验证成或p|


    SECTION 05 套用 Tomcat 4/5 ?JAASRealm

    建立 login.config 攑ֈ $CATALINA_HOME/conf/ 之中, 范例采用 MS SQLServer, jTds.sf.net ?jdbc driver
    JAASLoginModule
    {
    com.tagish.auth.DBLogin required dbDriver="net.sourceforge.jtds.jdbc.Driver" 
    dbURL="jdbc:jtds:sqlserver://localhost:1433/JAASDB" 
    dbUser="sa" 
    dbPassword="sa_password"
    userTable="Users"
    roleTable="Roles"
    roleMapTable="RoleMap";
    };
    
    ?tomcat 启动脚本中加?BR> JAVA_OPTS=-Djava.security.auth.login.config==C:\tomcat4\conf\login.config q且修改 server.xml, ?appName d?login.config 中的 JAASLoginModule, 以及讄 User/Group 相关?Principal
    <Realm className="org.apache.catalina.realm.JAASRealm"                 
    			 appName="JAASLoginModule"
    		 userClassNames="com.tagish.auth.TypedPrincipal"       
    		 roleClassNames="com.tagish.auth.TypedPrincipal" 
    			debug="99"/>
    
    最后设|?web.xml 中的 login-config 以及要保护的数据, 例如
    		
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>User Protected</web-resource-name>
          <url-pattern>/protected/*</url-pattern>
          <url-pattern>/protected.jsp</url-pattern>
        </web-resource-collection>
        <auth-constraint>
           <role-name>user</role-name>
        </auth-constraint>
      </security-constraint>
      <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>MyJAASRealm</realm-name>
      </login-config>
    
    SECTION 06 l论

    JAAS 除了在一?Desktop Application 应用之外, ?J2EE 支持会是一个主? 无论?JSR 196: Java Authentication Service Provider Interface for Containers q??JSR 115: Java Authorization Contract for Containers ( 已经U_ J2EE 1.4 之中 ) 都是?container 提供者要求标准的 provider 界面, 因此, 来开发相关的E序最好能够遵?JAAS, 在异构^台的整合 ? 才能具备完整的相Ҏ(gu)?

    my java 2005-08-17 15:48 发表评论
    ]]>
    WEB应用中的基本w䆾验证和表单n份验?中文)http://www.aygfsteel.com/lmsun/articles/10307.htmlmy javamy javaWed, 17 Aug 2005 02:07:00 GMThttp://www.aygfsteel.com/lmsun/articles/10307.htmlhttp://www.aygfsteel.com/lmsun/comments/10307.htmlhttp://www.aygfsteel.com/lmsun/articles/10307.html#Feedback0http://www.aygfsteel.com/lmsun/comments/commentRss/10307.htmlhttp://www.aygfsteel.com/lmsun/services/trackbacks/10307.htmlTranslated by Caiyi0903(Willpower)Q?004.4.23

    在Q何一UWEB应用开发中Q不论大中小规模的,每个开发者都会遇C些需要保护程序数据的问题Q涉及到用户的LOGIN ID和PASSWORD。那么如何执行验证方式更好呢Q实际上Q有很多方式来实现。在本文里,我们不会把所有的验证Ҏ(gu)都考虑刎ͼ我们的目的是让你学会如何以最单最方便的验证方法来完成。下面将讨论基本的(BASICQ和Z表单的(FORM-BASEDQ验证方式。我们考虑使用TOMCAT作ؓWEB SERVERQ它通过server.xml和web.xml文g提供基本的和Z表单的验证。JSP面中的j_security_check 表单(for FORM-based) 需要两个参敎ͼj_username和j_password。它们指定了在SQL数据库中的登陆角艌Ӏ你能够看到Q它的弹性化Q可用性和必要性?/P>

    W一步,我们要下载TOMCAT和MYSQLQ前者用来做WEB SERVERQ后者用来做SQL SERVER。还要下载JDBCRealm工具Q它在TOMCAT中用,用来做MYSQLq接器,q接MYSQL数据库的?/P>

    我们假设你已l安装了TOMCAT和MYSQLQ那么我们开始从SERVER的配|入手了。当Ӟ你还需要安装JAVA的MYSQLq接驱动Q我强烈只用稳定的驱动版本Q因为在有些情况下,alpha/beta版本的驱动不能正常工作?/P>

    下面我们来操作SQL数据库。老实_MYSQL和TOMCAT是相当好的工P它们都是跨^台的Q不你的操作系l是WINDOWSq是cMUNIX/LINUX的,它们都能正常q行。因此,不论q行环境Q它们的配置q程都是l对一L?/P>

    MySQL
    在命令行中执行mysql 客户端命令,然后输入Q?/P>

    create database weblogin;
    q个ؓ你创Z个weblogin数据库,它将保存用户名和密码以及角色{一切信息。你Ҏ(gu)据库所做的M改变都会直接立即反映出来。比如说d用户Q改变用户密码和角色{?/P>


    create table users (
       login varchar (15) not null,
       pass varchar (15) not null,
       primary key (login)
    );

    我们创徏一个users表用来保存用LLOGIN和PASSWORDQ?/P>


    create tables groups (
       login varchar (15) not null,
       group varchar (15) not null,
       primary key (login, group)
    );

    如你看到的,我们要在group表里保存login属于哪个group的信息。下面,我们要插于一些数据用来测试用,q完成MYSQL的配|工作:

    insert into users  ('green', 'testpwd');
    insert into groups ('green', 'testgroup');


    现在Q我们创Z一个用户叫greenQ他的密码是testpwdQ他属于testgroupq个用户l。接着Q轮到TOMCAT的配|了?/P>

    Tomcat
    TOMCAT本nq没有能力操作数据库来实现n份验证。但是可以依靠JDBCRealm。下面我们来使用它?/P>

    下面我们从TOMCAT的\conf\server.xml文g来开始我们的配置。打开q个文gq找C面的内容:

    <Realm className="org.apache.catalina.realm.MemoryRealm" />
    删除q一行,或者用<!-- ... --> 注释掉它,我们要用JDBCRealm。所以输入下面的内容:


    <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
       driverName="org.gjt.mm.mysql.Driver"
       connectionURL="jdbc:mysql://localhost/weblogin?user=test&password=test"
       userTable="users" userNameCol="login" userCredCol="pass"
       userRoleTable="groups" roleNameCol="group" />

    下面我们对field参数做详l讲?

    debug—这是我们设|的debug参数Q数字越高显CZ息越详细?
    driverName—这个是MYSQL驱动的名字。要保q个驱动的JAR包在TOMCAT的CLASSPATH中能够找到它?
    connectionURL—这个是用来建立JDBCq接的数据库URL。在q个field里,weblogin是我们数据库的名字。user和password 是我们登陆数据库的用h据?
    userTable—一个定义有userNameCol和userCredCol字段的表?
    userNameCol和userCredCol—users表里定义的login和pass?
    现在Q我们完成了配置q程。下面,我们要配|WEB应用E序来被q样一个n份验证方式保护v来。我们要举两个例子。最单的是基本n份验证方式,然后是Z表单的n份验证。在W一U情况里Q我们尝试访问受保护的数据,会有一个POP-UPH口弹出提示你输入你的login和password。在W二U情况里Q我们会通过面的方式来让你通过w䆾验证。这个页面的内容可以是Q意的Q这个取决于你要使用怎么L验证方式了?/P>

    基本w䆾验证方式QBASIC authorization methodQ?BR>我们假设应用E序在TOMCAT的\webapps\webdemo, 我们要保护所有在admin 子目录里的文件。我们必L开它的\webapps\webdemo\WEB-INF\web.xml文gQ输入下列内?


    <security-constraint>
       <web-resource-collection>
          <web-resource-name>Web Demo</web-resource-name>
          <url-pattern>/admin/*</url-pattern>
       </web-resource-collection>
       <auth-constraint>
          <role-name>testgroup</role-name>
       </auth-constraint>
    </security-constraint>
    <login-config>
       <auth-method>BASIC</auth-method>
       <realm-name>Web Demo</realm-name>
    </login-config>

    让我们来看看刚才输入的内宏V我们ؓ应用E序创徏了一个web-resource-nameq映到l(f)ogin-config 。我们还定义了url-pattern, 它指明你受保护程序的路径。在login-conf中,我们定义了一个BASIC auth-method?/P>

    很简单,对吗Q不要忘CQ在使改变生效前要停止ƈ重启TOMCAT?/P>

    表单w䆾验证方式QFORM-based authorization methodQ?BR>对于q种方式Q我们仅仅只需?

    修改\webapps\webdemo\WEB-INF\web.xml
    创徏一个登陆用的JSP面, 用户在q里的HTML表单中输入他的登陆ID和密?
    创徏一个JSP error面Q一旦验证失败,用户蟩到该面
    如果你先试使用BASIC验证方式Q你只需要改变login-config Z面那一D代码。否则,你需要输入security-constraint代码Dc用下面的login-config:


    <login-config>
       <auth-method>FORM</auth-method>
       <realm-name>Web Demo</realm-name>
       <form-login-config>
          <form-login-page>/admin/login.jsp</form-login-page>
          <form-error-page>/admin/error.jsp</form-error-page>
       </form-login-config>
    </login-config>

    我们讄表单的auth-methodq定义了form-login-config。这个将使得TOMCAT使用 \admin\login.jsp面来让用户登陆Q用\admin\error.jsp面来处理登陆失败?/P>

    你可以用Q何你惌的出错信息。页面唯一需要的是下面的HTML表单标签Q你要插到页面中Q?/P>


    ...
    <form method="POST" action="j_security_check">
       <input type="text" name="j_username">
       <input type="text" name="j_password">
       <input type="submit" value="Log in">
    </form>
    ...

    布局Q风|或其他所有你喜欢的。这个error面能够做成M你想要的。无非就是通知用户Q验证失败了?/P>

    OKQ全部完成了。你需要停止和重启一遍TOMCAT使得改变生效?/P>

    © Olexiy Prokhorenko, http://www.7dots.com/resume/
    Co-author: Alexander Prohorenko



    my java 2005-08-17 10:07 发表评论
    ]]>
    利用Tocmat安全域实现安全认?/title><link>http://www.aygfsteel.com/lmsun/articles/10304.html</link><dc:creator>my java</dc:creator><author>my java</author><pubDate>Wed, 17 Aug 2005 01:57:00 GMT</pubDate><guid>http://www.aygfsteel.com/lmsun/articles/10304.html</guid><wfw:comment>http://www.aygfsteel.com/lmsun/comments/10304.html</wfw:comment><comments>http://www.aygfsteel.com/lmsun/articles/10304.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lmsun/comments/commentRss/10304.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lmsun/services/trackbacks/10304.html</trackback:ping><description><![CDATA[<P>安全域功能是Tomcat内置功能,在org.apache.catalina.Realm接口中声明了把一l用户名、口令及所兌的角色集成到Tocmat中的Ҏ(gu)?/P> <P>内存域:MemoryRealm 从XML文g中读取安全验证信息ƈ存入内存中?BR>JDBC域:JDBCRealm 通过JDBC驱动E序讉K存放在数据库中的信息?BR>数据源域QDataSourceRealm 通过JDBC数据源访问存攑֜数据库中的信息?BR>JNDI域:JNDIRealm 通过JNDI provider讉K存放在基于LDAP的目录服务器中的安全验证信息?/P> <P>讄资源安全U束</P> <P>在web.xml中加?lt;security-constraint>元素</P> <P><security-constraint><BR> <display-name>MZT</display-name><BR> <web-resource-collection><BR>   <web-resource-name>protected test</web-resource-name><BR>   <url-pattern>/test/*</url-pattern><BR>   <http-method>POST</http-method><BR>   <http-method>GET</http-method><BR> </web-resource-collection><BR> <auth-constraint><BR>  <role-name>mztadmin</role-name><BR> </auth-constraint><BR></security-constraint><BR><login-config><BR> <auth-method>BASIC</auth-method><BR> <realm-name>test realm</realm-name><BR></login-config></P> <P><BR>讄JDBC?/P> <P><Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"<BR>driverName="org.gjt.mm.mysql.Driver"<BR>connectionURL="jdbc:mysql://localhost/mzt"<BR>connectionName="root" connectionPassword=""<BR>userTable="users" userNameCol="user_name" userCredCol="user_pass"<BR>userRoleTable="user_roles" roleNameCol="role_name" /></P> <P><BR><Realm className="org.apache.catalina.realm.DataSourceRealm" debug="99"<BR>dataSourceName="jdbc/tomcatusers"<BR>userTable="users" userNameCol="user_name" userCredCol="user_pass"<BR>userRoleTable="user_roles" roleNameCol="role_name"/></P> <P><BR>在MySQL中执行以下SQL语句:</P> <P>#########</P> <P>#用户?BR>create table users(<BR>user_name varchar(15) not null primary key,<BR>user_pass varchar(15) not null<BR>);</P> <P>#用户角色?BR>create table user_roles(<BR>user_name varchar(15) not null,<BR>role_name varchar(15) not null,<BR>primary key(user_name, role_name)<BR>);</P> <P>insert into users values('mzt','test');<BR>insert into user_roles values('mzt','mztadmin');<BR></P><img src ="http://www.aygfsteel.com/lmsun/aggbug/10304.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lmsun/" target="_blank">my java</a> 2005-08-17 09:57 <a href="http://www.aygfsteel.com/lmsun/articles/10304.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Web应用中用BASIC和基于Form的验?/title><link>http://www.aygfsteel.com/lmsun/articles/10301.html</link><dc:creator>my java</dc:creator><author>my java</author><pubDate>Wed, 17 Aug 2005 01:45:00 GMT</pubDate><guid>http://www.aygfsteel.com/lmsun/articles/10301.html</guid><wfw:comment>http://www.aygfsteel.com/lmsun/comments/10301.html</wfw:comment><comments>http://www.aygfsteel.com/lmsun/articles/10301.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lmsun/comments/commentRss/10301.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lmsun/services/trackbacks/10301.html</trackback:ping><description><![CDATA[<P>大家司空见惯了用自q机制q行用户的验证,其实QTomcat本n对用户的认证提供了支持Q用Tomcat自n的认证功能,只需要进行一些简单的配置可以完成用L验证功能。如果还没有使用q,读读q篇文章吧?/P> <P>BASIC and FORM-based Authorization in Your Web Application<BR>By Olexiy & Alexander Prokhorenko</P> <P>In the development of any, more-or-less big Web application, every developer collides at times with the problem of how to bear certain parts of the application in the protected area and to divide access to them by login and password. How do you carry out authentication? Actually, there are a lot of variants. In this article, we do not present a problem to consider all possibilities; our purpose is to learn how to work with the simplest yet rather convenient method of authorization. We will talk about BASIC and FORM-based authorizations. As a Web server, we will consider Tomcat, which provides BASIC and FORM-based authentication through server.xml and web.xml files; the use of a j_security_check form (for FORM-based) in a JSP page that requires two parameters j_username and j_password; and specifying roles (groups) within the SQL database. As you can see, it's a flexible, useful, and necessary set of capabilities.</P> <P>To begin with, you need to download Tomcat, which we will use as a Web server and MySQL, which we will use as a SQL server. Also, you need to download the JDBCRealm tool which will be used with Tomcat, and the MySQL Connector/J to use with MySQL.</P> <P>We assume you have installed Tomcat and MySQL properly, so we can start right from the server's configuration. Of course, you also need to install the MySQL Connector/J driver, and I strongly recommend using only stable releases of the driver because, in some cases, alpha/beta versions of the driver do not work in the given sheaf.</P> <P>First of all, we will work with the SQL database. Honestly speaking, MySQL, as well as Tomcat, is pretty universal, and doesn't depend on the OS in which you are using it (Windows or Unix-like system), so the process of configuration will be absolutely the same; it doesn't matter where you run it.</P> <P><BR>MySQL</P> <P>Execute the mysql client from the installation binary directory and type:</P> <P>create database weblogin;<BR>This will create the weblogin database in which we will keep user names, passwords, roles?everything. Thus, any changes you have made to the database directly (new users, changed passwords or roles, and so forth) will be reflected immediately.</P> <P><BR>create table users (<BR>   login varchar (15) not null,<BR>   pass varchar (15) not null,<BR>   primary key (login)<BR>);</P> <P>We will keep the user's login and password in this users table.</P> <P><BR>create tables groups (<BR>   login varchar (15) not null,<BR>   group varchar (15) not null,<BR>   primary key (login, group)<BR>);</P> <P>As you can see, we will keep information about which login belongs to which group in this groups table. Let's fill our tables with some test data and finish the process of MySQL configuration:</P> <P><BR>insert into users  ('green', 'testpwd');<BR>insert into groups ('green', 'testgroup');</P> <P>So, we created the user green with the password testpwd in the group testgroup. And now, it's Tomcat's turn to be configured.</P> <P><BR>Tomcat</P> <P>Tomcat itself has no ability to work with the database to carry out authentication. However, there is JDBCRealm for these purposes; we are going to use that.</P> <P>We will start our configuration from Tomcat's \conf\server.xml file. Open this file and find the following string:</P> <P><Realm className="org.apache.catalina.realm.MemoryRealm" /><BR>Remove this line or just comment it by using <!-- ... --> Instead of it, we will use JDBCRealm. Type the following:</P> <P><BR><Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"<BR>   driverName="org.gjt.mm.mysql.Driver"<BR>   connectionURL="jdbc:mysql://localhost/weblogin?user=test&password=test"<BR>   userTable="users" userNameCol="login" userCredCol="pass"<BR>   userRoleTable="groups" roleNameCol="group" /></P> <P>We will consider all mentioned fields in a bit more detail:</P> <P>debug?Here, we set the debug level. A higher number generates more detailed output. <BR>driverName?The name of our MySQL driver. You need to be sure that the driver's JAR file is located in Tomcat's CLASSPATH. <BR>connectionURL?The database URL that is used to establish a JDBC connection. In this field, weblogin is the name of our database; user and password are login data with which you are connecting to the database. In MySQL, such a user is created by default, so you can use it. In case you don't have such a user, you need to create your own user and make it capable of working with your weblogin database. <BR>userTable?A table with at least two fields, defined in userNameCol and userCredCol. <BR>userNameCol and userCredCol?The fields with the name of login field from the users table and pass. <BR>Now, we are at the stage of finishing the configuration process. We need to configure your Web application to be protected with such an authentication. Below, we show examples of two configurations. The simplest is a BASIC authentification method, and a little more original method is a FORM-based one. In the first case at attempting to access the protected area, a pop-up window will appear with the requirement to enter your login and password. In the second case, we will get a page on which we will pass authentification on our defined JSP. The contents of a page can be anything; it should meet only few simple requirements on the contents of a HTML <form> tag. It is up to you what authorization methods you will use.</P> <P><BR>Basic authorization method</P> <P>Let's assume that our Web application is located in Tomcat's \webapps\webdemo, and we need to protect all files placed in the admin subdirectory. We need to open its \webapps\webdemo\WEB-INF\web.xml file and type the following text:</P> <P><BR><security-constraint><BR>   <web-resource-collection><BR>      <web-resource-name>Web Demo</web-resource-name><BR>      <url-pattern>/admin/*</url-pattern><BR>   </web-resource-collection><BR>   <auth-constraint><BR>      <role-name>testgroup</role-name><BR>   </auth-constraint><BR></security-constraint><BR><login-config><BR>   <auth-method>BASIC</auth-method><BR>   <realm-name>Web Demo</realm-name><BR></login-config></P> <P>Let me say a few words about what we just did. We created web-resource-name for our application and mapped login-config to this resource. We defined url-pattern, which has information about which sub-directory of our entire application will be protected, and which role-name is allowed to access the protected area. In login-conf, we defined a BASIC auth-method.</P> <P>Pretty easy, isn't it? Do not forget to stop and re-start Tomcat to make these our changes work.</P> <P> </P> <P>FORM-based authorization method</P> <P>For this method, we will only need to:</P> <P>Modify \webapps\webdemo\WEB-INF\web.xml <BR>Create a login JSP page, on which the user will get a HTML form to enter his login and password <BR>Create a JSP error page that the user will get if an error happened during authorization <BR>So, let's start from the very beginning. In case you tried the BASIC authorization method first, you need just to change the login-config section to the one listed below. Otherwise, you need to type the security-constraint section from the BASIC method (it's absolutely the same), but use the following login-config:</P> <P><BR><login-config><BR>   <auth-method>FORM</auth-method><BR>   <realm-name>Web Demo</realm-name><BR>   <form-login-config><BR>      <form-login-page>/admin/login.jsp</form-login-page><BR>      <form-error-page>/admin/error.jsp</form-error-page><BR>   </form-login-config><BR></login-config></P> <P>We set the FORM's auth-method and defined the form-login-config section; this will force Tomcat to use the \admin\login.jsp page as the page with the HTML form for the user to sign in, and use \admin\error.jsp in case the login failed.</P> <P>You can have any login and error screen you like; the only requirement is that HTML <form> should be the following (to be more exact, it should have fields defined as such):</P> <P><BR>...<BR><form method="POST" action="j_security_check"><BR>   <input type="text" name="j_username"><BR>   <input type="text" name="j_password"><BR>   <input type="submit" value="Log in"><BR></form><BR>...</P> <P>The layout, styles, or whatever else could be anything you like. The error page could be anything you want; you will need to inform the user that there that something is wrong with the authentication.</P> <P>That is all. You need to stop and re-start Tomcat to make these changes work.</P> <P>© Olexiy Prokhorenko, <A >http://www.7dots.com/resume/</A><BR>Co-author: Alexander Prohorenko<BR></P><img src ="http://www.aygfsteel.com/lmsun/aggbug/10301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lmsun/" target="_blank">my java</a> 2005-08-17 09:45 <a href="http://www.aygfsteel.com/lmsun/articles/10301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用TOMCATZJDBC的的RealmQ?Q?/title><link>http://www.aygfsteel.com/lmsun/articles/10300.html</link><dc:creator>my java</dc:creator><author>my java</author><pubDate>Wed, 17 Aug 2005 01:41:00 GMT</pubDate><guid>http://www.aygfsteel.com/lmsun/articles/10300.html</guid><wfw:comment>http://www.aygfsteel.com/lmsun/comments/10300.html</wfw:comment><comments>http://www.aygfsteel.com/lmsun/articles/10300.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lmsun/comments/commentRss/10300.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lmsun/services/trackbacks/10300.html</trackback:ping><description><![CDATA[<P>摘要<BR>  Realm是一个用h据库的概念,cM于Unix中的用户组Q它通过用户名和密码来标识一个用Pq个用户属于一定的角色QroleQ。而一个特D的web应用资源Q可以限定某个角色的用户才被许可讉K。这U许可策略,使得web应用的整体权限控制与应用l节相剥,从而获得更好的可配|性。下面我们通过比较常见的基于数据库Q用直接JDBCq接的Realm的配|用情况,看看它是如何实现_粒度的ACL的?2004-03-13 11:21:34)</P> <P>--------------------------------------------------------------------------------<BR>By lanf</P> <P>应用TOMCATZJDBC的的Realm Q?Q?<BR>作(译)者:Lanf From LinuxAID </P> <P>Realm是一个用h据库的概念,cM于Unix中的用户组Q它通过用户名和密码来标识一个用Pq个用户属于一定的角色QroleQ。而一个特D的web应用资源Q可以限定某个角色的用户才被许可讉K。这U许可策略,使得web应用的整体权限控制与应用l节相剥,从而获得更好的可配|性。下面我们通过比较常见的基于数据库Q用直接JDBCq接的Realm的配|用情况,看看它是如何实现_粒度的ACL的?</P> <P>JDBCRealm </P> <P>JDBCRealm是用JDBCq接关系数据库的一个Tomcat 4 Realm接口的实现。它可以直接使用你现有的用户数据库表Q来获取角色用户的信息,完成验证。你必须满以下条gQ?/P> <P>必须有个有效的数据表Q里面有所有你需要通过Realm来认证的用户。这张表必须臛_有两个字D,可以用来标示用户名和密码?<BR>需要有一张表来标明用户与角色的对应关p,用户可以有Q意个角色Q没有角色也是合法的Q这是和UNIX用户组的不同之处。同栯个表也需要两个字D,来映用户名与角色名的对应关pR?<BR>数据库准?</P> <P>在我们的例子中,我们Z张新表来处理realm的认证?<BR>create table users (<BR>  user_name         varchar(15) not null primary key,<BR>  user_pass         varchar(15) not null<BR>);</P> <P>create table user_roles (<BR>  user_name         varchar(15) not null,<BR>  role_name         varchar(15) not null,<BR>  primary key (user_name, role_name)<BR>); <BR> </P> <P><BR>JDBC驱动 </P> <P>你需要将你的JDBC启动包放?$CATALINA_HOME/server/lib 目录或?$CATALINA_HOME/common/lib 目录下,保Tomcat能通过CLASSPATH扑ֈ它。用mysql数据库的话,你可以用类?mm.mysql-2.0.4-bin.jar 的驱动包QOracle 9i你可以用ojdbc14.jar{Oracle自带的驱动;PostgreSQL可以?A >http://jdbc.postgresql.org/</A> 取得合适的驱动E序?</P> <P>~辑server.xml </P> <P>~辑$CATALINA_HOME/conf/server.xml文gQ在host里添加如下片D(以MySQLZQ?<BR> <Realm className = 'org.apache.catalina.realm.JDBCRealm' debug='0'<BR>      driverName = 'org.gjt.mm.mysql.Driver'<BR>connectionURL = 'jdbc:mysql://localhost/authority?user=dbuser&password=dbpass'<BR>       userTable='users' userNameCol='user_name' userCredCol='user_pass'<BR>   userRoleTable='user_roles' roleNameCol='role_name'/></P> <P> </P> <P><BR>其中 jdbc:mysql://localhost/authority?user=dbuser&password=dbpass 是Mysql的连接串Q你可以Ҏ(gu)你的需要进行修攏V其有关属性介l如下: 属?描述 <BR>className Realm的实现类Q这里必L 'org.apache.catalina.realm.JDBCRealm' <BR> <BR>connectionName 数据库用户名<BR> <BR>connectionPassword 数据库用L密码<BR> <BR>connectionURL 数据库的JDBCq接?BR> <BR>debug Debug的程度,它和Logger相关配置配合使用QD高信息越详细Q缺省ؓ0<BR> <BR>digest 存储密码的加密方式,如果不指定则是明文存储。指定ؓ java.security.MessageDigest 之类的类名则要看数据库里表中用户密码的存放格式?<BR> <BR>driverName 数据库驱动程序类<BR> <BR>roleNameCol 角色表的存放角色名的字段?<BR> <BR>userCredCol 用户表里存放密码的字D名<BR> <BR>userNameCol 用户表中存放用户名的字段?BR> <BR>userRoleTable 角色表的表名Q类?etc/groupQ?BR> <BR>userTable 用户表的表名<BR> </P> <P><BR>注意?</P> <P>如果你对用户表进行了新增操作和修Ҏ(gu)作,那么会实时作用于正要q行登陆操作的用P <BR>用户已经完成登陆后,你对它进行的删除修改操作Qƈ不能实时作用于用L当前状态,只能在此用户下次登陆的时候生效;Q如果是Z表单认证的用P是在会话l束或者他注销后当前认证失效;如果是基认证的用户则需要等到当前窗口关闭) <BR>Ҏ(gu)据库里那两个表的增删改管理,你需要自行编写合适的业务代码QTomcatq没有提供标准的实现Q这是没有意义的?<BR>~译者注Q这部分内容是帮助newbie理解Realm而直接从Realm Configuration HOW-TO中摘译的Q是我们完整例子所必须要了解ƈ正确配置的部分,不过g没有看到cM的译文,做了这件篏赘的事情。这pd文章对熟手基本没有什么帮助,误谅?</P> <P> </P><img src ="http://www.aygfsteel.com/lmsun/aggbug/10300.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lmsun/" target="_blank">my java</a> 2005-08-17 09:41 <a href="http://www.aygfsteel.com/lmsun/articles/10300.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat5.0+mysql配置JDBCRealm,DBCP,ssl,及中文ؕ码解册?/title><link>http://www.aygfsteel.com/lmsun/articles/10299.html</link><dc:creator>my java</dc:creator><author>my java</author><pubDate>Wed, 17 Aug 2005 01:38:00 GMT</pubDate><guid>http://www.aygfsteel.com/lmsun/articles/10299.html</guid><wfw:comment>http://www.aygfsteel.com/lmsun/comments/10299.html</wfw:comment><comments>http://www.aygfsteel.com/lmsun/articles/10299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lmsun/comments/commentRss/10299.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lmsun/services/trackbacks/10299.html</trackback:ping><description><![CDATA[<P>准备环境:<BR>1.j2sdk-1_4_2-windows-i586.exe    //jdk<BR>2.mysql-4.0.20d-win.zip        //mysql数据?BR>3.mysqlcc-0.9.4-win32.zip    //mysqlGUI控制<BR>4.jakarta-tomcat-5.0.27.exe    //tomcat服务?BR>5.mysql-connector-java-3.0.14-production.zip //内含mysql驱动</P> <P>安装步骤:<BR>1.安装jdk<BR>2.安装tomcat<BR>3.安装mysql<BR>4.安装mysqlcc<BR>5.驱动包解压,拯mysql-connector-java-3.0.14-production-bin.jar到tomcat/common/lib?BR>或者下载mm.mysql-2.0.14-you-must-unjar-me.jar,解压后拷贝其中的mm.mysql-2.0.14-bin.jar</P> <P>Tomcat5.0配置 本例使用安装密码 198277<BR>1.配置manager 理应用E序<BR>在conf/server.xml ?BR>d如下</P> <P><Service name="Catalina"><BR>...</P> <P>    <Context path="/manager" debug="0" privileged="true"<BR>             docBase="/usr/local/kinetic/tomcat5/server/webapps/manager"><BR>    </Context></P> <P></Service> </P> <P>限制ip讉K配置<BR><Context path="/manager" debug="0" privileged="true"<BR>         docBase="/usr/local/kinetic/tomcat5/server/webapps/manager"><BR>         <Valve className="org.apache.catalina.valves.RemoteAddrValve"<BR>                allow="127.0.0.1"/><BR></Context><BR>试?http://localhost:8080/manager/html</P> <P>2.配置JDBCRealm容器理安全,以mysql-4.0数据库ؓ?BR>a.拯驱动mm.mysql-2.0.14-bin.jar到common/lib/?BR>b.在数据库ycg中徏?BR>   <BR> create table users (<BR>  user_name         varchar(15) not null primary key,<BR>  user_pass         varchar(15) not null<BR>);</P> <P>create table user_roles (<BR>  user_name         varchar(15) not null,<BR>  role_name         varchar(15) not null,<BR>  primary key (user_name, role_name)<BR>);</P> <P>c.修改server.xml如下(默认数据库ؓroot,无密?如果有Ş?connectionURL="jdbc:mysql://localhost/authority?</P> <P>user=dbuser&password=dbpass")<BR>      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"<BR>             driverName="org.gjt.mm.mysql.Driver"<BR>          connectionURL="jdbc:mysql://localhost/ycg?user=root"<BR>         connectionName="" connectionPassword=""<BR>              userTable="users" userNameCol="user_name" userCredCol="user_pass"<BR>          userRoleTable="user_roles" roleNameCol="role_name" /></P> <P>d.在数据库中添加入tomcat的默认配|数?</P> <P>+-----------+-----------+<BR>| user_name | role_name |<BR>+-----------+-----------+<BR>| admin     | admin     |<BR>| admin     | manager   |<BR>| both      | role1     |<BR>| both      | tomcat    |<BR>| role1     | role1     |<BR>| tomcat    | tomcat    |<BR>+-----------+-----------+<BR>+-----------+-----------+<BR>| user_name | user_pass |<BR>+-----------+-----------+<BR>| tomcat    | tomcat    |<BR>| both      | tomcat    |<BR>| role1     | tomcat    |<BR>| admin     | 198277    |<BR>+-----------+-----------+</P> <P>e.启动mysql,启动tomcat,此后tomcat从数据库中ȝ戯则认?默认的conf/tomcat-users.xml失效</P> <P>3.DBCP的配|?BR>a.讄<BR>             <parameter><BR>              <name>removeAbandoned</name><BR>              <value>true</value><BR>            </parameter></P> <P> 可失效的数据连接重新启?<BR>配套讄<BR>   <BR>             <parameter><BR>              <name>removeAbandonedTimeout</name><BR>              <value>60</value><BR>            </parameter><BR>失效旉<BR>如果要写入日?BR>讄<BR>            <parameter><BR>              <name>logAbandoned</name><BR>              <value>true</value><BR>            </parameter><BR>以上三个默认都是false<BR>b.以mysqlZ,配置数据q接?BR>c.配置新的用户与数据库,必须讑֮密码,I密码将Dq接p|<BR>e.<BR>指定root密码:mysqladmin -u root -h localhost password "198277"<BR>(需修改上面的jdbcrealm讄connectionURL="jdbc:mysql://localhost/ycg?user=root&password=198277")<BR>命omysqlq入匿名q接到服务器<BR>密码讉K<BR>shell> mysql -h host -u user -p<BR>Enter password: ********</P> <P>//如果root没有密码,以下是不成功?(试过?<BR> mysql> GRANT ALL PRIVILEGES ON *.* TO <A href="mailto:javauser@localhost">javauser@localhost</A> <BR>    ->   IDENTIFIED BY 'javadude' WITH GRANT OPTION;<BR>mysql> create database javatest;<BR>mysql> use javatest;<BR>mysql> create table testdata (<BR>    ->   id int not null auto_increment primary key,<BR>    ->   foo varchar(25), <BR>    ->   bar int);</P> <P>在conf/server.xml?lt;host></host>中添?BR><Context path="/DBTest" docBase="DBTest"<BR>        debug="5" reloadable="true" crossContext="true"></P> <P>  <Logger className="org.apache.catalina.logger.FileLogger"<BR>             prefix="localhost_DBTest_log." suffix=".txt"<BR>             timestamp="true"/></P> <P>  <Resource name="jdbc/TestDB"<BR>               auth="Container"<BR>               type="javax.sql.DataSource"/></P> <P>  <ResourceParams name="jdbc/TestDB"><BR>    <parameter><BR>      <name>factory</name><BR>      <value>org.apache.commons.dbcp.BasicDataSourceFactory</value><BR>    </parameter></P> <P>    <!-- Maximum number of dB connections in pool. Make sure you<BR>         configure your mysqld max_connections large enough to handle<BR>         all of your db connections. Set to 0 for no limit.<BR>         --><BR>    <parameter><BR>      <name>maxActive</name><BR>      <value>100</value><BR>    </parameter></P> <P>    <!-- Maximum number of idle dB connections to retain in pool.<BR>         Set to 0 for no limit.<BR>         --><BR>    <parameter><BR>      <name>maxIdle</name><BR>      <value>30</value><BR>    </parameter></P> <P>    <!-- Maximum time to wait for a dB connection to become available<BR>         in ms, in this example 10 seconds. An Exception is thrown if<BR>         this timeout is exceeded.  Set to -1 to wait indefinitely.<BR>         --><BR>    <parameter><BR>      <name>maxWait</name><BR>      <value>10000</value><BR>    </parameter></P> <P>    <!-- MySQL dB username and password for dB connections  --><BR>    <parameter><BR>     <name>username</name><BR>     <value>javauser</value><BR>    </parameter><BR>    <parameter><BR>     <name>password</name><BR>     <value>javadude</value><BR>    </parameter></P> <P>    <!-- Class name for the old mm.mysql JDBC driver - uncomment this entry and comment next<BR>         if you want to use this driver - we recommend using Connector/J though<BR>    <parameter><BR>       <name>driverClassName</name><BR>       <value>org.gjt.mm.mysql.Driver</value><BR>    </parameter><BR>     --><BR>    <BR>    <!-- Class name for the official MySQL Connector/J driver --><BR>    <parameter><BR>       <name>driverClassName</name><BR>       <value>com.mysql.jdbc.Driver</value><BR>    </parameter><BR>    <BR>    <!-- The JDBC connection url for connecting to your MySQL dB.<BR>         The autoReconnect=true argument to the url makes sure that the<BR>         mm.mysql JDBC Driver will automatically reconnect if mysqld closed the<BR>         connection.  mysqld by default closes idle connections after 8 hours.<BR>         --><BR>    <parameter><BR>      <name>url</name><BR>      <value>jdbc:mysql://localhost:3306/javatest?autoReconnect=true</value><BR>    </parameter></P> <P><BR>            <parameter><BR>              <name>removeAbandoned</name><BR>              <value>true</value><BR>            </parameter></P> <P>             <parameter><BR>              <name>removeAbandonedTimeout</name><BR>              <value>60</value><BR>            </parameter><BR>            <parameter><BR>              <name>logAbandoned</name><BR>              <value>true</value><BR>            </parameter><BR>  </ResourceParams><BR></Context></P> <P>f.在web服务中调?配置web.xml ?<BR><web-app xmlns="<A <BR>    xmlns:xsi="<A <BR>    xsi:schemaLocation="<A >http://java.sun.com/xml/ns/j2ee</A><BR><A <BR>    version="2.4"><BR>  <description>MySQL Test App</description><BR>  <resource-ref><BR>      <description>DB Connection</description><BR>      <res-ref-name>jdbc/TestDB</res-ref-name><BR>      <res-type>javax.sql.DataSource</res-type><BR>      <res-auth>Container</res-auth><BR>  </resource-ref><BR></web-app><BR>g.试用test.jsp <BR><%@ taglib uri="<A prefix="sql" %><BR><%@ taglib uri="<A prefix="c" %></P> <P><sql:query var="rs" dataSource="jdbc/TestDB"><BR>select id, foo, bar from testdata<BR></sql:query></P> <P><html><BR>  <head><BR>    <title>DB Test</title><BR>  </head><BR>  <body></P> <P>  <h2>Results</h2><BR>  <BR><c:forEach var="row" items="${rs.rows}"><BR>    Foo ${row.foo}<br/><BR>    Bar ${row.bar}<br/><BR></c:forEach></P> <P>  </body><BR></html></P> <P>h.新徏web应用<BR>下蝲jakarta-taglibs-standard-1.1.0<BR>copy jstl.jar and standard.jar to your web app's WEB-INF/lib </P> <P>DBTest/<BR>    WEB-INF/<BR>        web.xml<BR>        lib/<BR>            jstl.jar<BR>            standard.jar<BR>    test.jsp<BR>拯到webapps/ ?BR>i.启动mysql,tomcat <BR>讉K:<BR><A href="http://localhost:8080/DBTest/test.jsp">http://localhost:8080/DBTest/test.jsp</A><BR>昄:<BR>    Results<BR>    Foo hello<BR>    Bar 12345</P> <P>4.ssl的配|?以jdk1.4.2Z<BR>a.q入%JAVA_HOME%\bin<BR>q行命o:keytool -genkey -alias tomcat -keyalg RSA<BR>以tomcat 安装密码?98277,ketool讄密码?98277Z<BR>输入keystore密码Q?nbsp; 198277<BR>(zhn)的名字与姓氏是什么?<BR>  [Unknown]Q?nbsp; ycg<BR>(zhn)的l织单位名称是什么?<BR>  [Unknown]Q?nbsp; nju<BR>(zhn)的l织名称是什么?<BR>  [Unknown]Q?nbsp; nju<BR>(zhn)所在的城市或区域名U是什么?<BR>  [Unknown]Q?nbsp; nanjing<BR>(zhn)所在的州或省䆾名称是什么?<BR>  [Unknown]Q?nbsp; jiangsu<BR>该单位的两字母国家代码是什?BR>  [Unknown]Q?nbsp; nd<BR>CN=ycg, OU=nju, O=nju, L=nanjing, ST=jiangsu, C=nd 正确吗?<BR>  [否]Q?nbsp; y</P> <P>输入<tomcat>的主密码<BR>        Q如果和 keystore 密码相同Q按回RQ:  198277<BR>b.在你的D:\Documents and Settings\的当前用L录下可以扑ֈ.keystore文g.其拯到conf/文g夹下.<BR>c.在server.xml 中找?/P> <P>    <!--<BR>    <Connector port="8443" <BR>               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<BR>               enableLookups="false" disableUploadTimeout="true"<BR>               acceptCount="100" debug="0" scheme="https" secure="true"<BR>               clientAuth="false" sslProtocol="TLS" /><BR>    --><BR>    L注释</P> <P>d配置字段:keystoreFile="/conf/.keystore" keystorePass="198277"<BR>? <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --><BR>   <BR>    <Connector port="8443" <BR>               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<BR>               enableLookups="false" disableUploadTimeout="true"<BR>               acceptCount="100" debug="0" scheme="https" secure="true"<BR>               clientAuth="false" sslProtocol="TLS" keystoreFile="/conf/.keystore"<BR>               keystorePass="198277"/><BR>d.试?<BR><A href="https://localhost:8443">https://localhost:8443</A><BR>e.在自qE序中添加ssl认证方式?<BR>在web.xml ?lt;web-app></web-app>d<BR><security-constraint><BR><web-resource-collection><BR><web-resource-name>Success</web-resource-name><BR><url-pattern>/</url-pattern><BR><http-method>GET</http-method><BR><http-method>POST</http-method><BR></web-resource-collection><BR><user-data-constraint><BR><transport-guarantee>CONFIDENTIAL</transport-guarantee><BR></user-data-constraint><BR></security-constraint><BR>f.用上提ؓ例就?BR>修改web.xml ?BR><web-app xmlns="<A <BR>    xmlns:xsi="<A <BR>    xsi:schemaLocation="<A >http://java.sun.com/xml/ns/j2ee</A><BR><A <BR>    version="2.4"></P> <P>    <description>MySQL Test App</description></P> <P><security-constraint><BR><web-resource-collection><BR><web-resource-name>Success</web-resource-name><BR><url-pattern>/</url-pattern><BR><http-method>GET</http-method><BR><http-method>POST</http-method><BR></web-resource-collection><BR><user-data-constraint><BR><transport-guarantee>CONFIDENTIAL</transport-guarantee><BR></user-data-constraint><BR></security-constraint></P> <P>  <BR>  <resource-ref><BR>      <description>DB Connection</description><BR>      <res-ref-name>jdbc/TestDB</res-ref-name><BR>      <res-type>javax.sql.DataSource</res-type><BR>      <res-auth>Container</res-auth><BR>  </resource-ref><BR></web-app><BR>讉K:<BR><A href="https://localhost:8443/DBTest/test.jsp">https://localhost:8443/DBTest/test.jsp</A></P> <P>g.如果?配置的jdbcRealml合hq行表单认证<BR>先在user_roles表中duser_name:ycg role_name:web-user<BR>在users表中duser_name:ycg user_pass:198277</P> <P>然后在web.xml中添?BR><auth-constraint><BR><role-name>web-user</role-name><BR></auth-constraint></P> <P><login-config><BR> <auth-method>BASIC</auth-method><BR> <realm-name>My Member Area</realm-name><BR></login-config></P> <P>修改后的web.xml?<BR><web-app xmlns="<A <BR>    xmlns:xsi="<A <BR>    xsi:schemaLocation="<A >http://java.sun.com/xml/ns/j2ee</A><BR><A <BR>    version="2.4"></P> <P>    <description>MySQL Test App</description></P> <P><security-constraint><BR><web-resource-collection><BR><web-resource-name>Success</web-resource-name><BR><url-pattern>/</url-pattern><BR><http-method>GET</http-method><BR><http-method>POST</http-method><BR></web-resource-collection><BR><auth-constraint><BR><role-name>web-user</role-name><BR></auth-constraint><BR><user-data-constraint><BR><transport-guarantee>CONFIDENTIAL</transport-guarantee><BR></user-data-constraint><BR></security-constraint><BR><login-config><BR> <auth-method>BASIC</auth-method><BR> <realm-name>My Member Area</realm-name><BR></login-config><BR>  <BR>  <resource-ref><BR>      <description>DB Connection</description><BR>      <res-ref-name>jdbc/TestDB</res-ref-name><BR>      <res-type>javax.sql.DataSource</res-type><BR>      <res-auth>Container</res-auth><BR>  </resource-ref><BR></web-app></P> <P>试:<BR><A href="http://localhost:8080/DBTest/test.jsp">http://localhost:8080/DBTest/test.jsp</A><BR>通过sslq接,q进行表单认?用户密码可在user_roles,和users中添?</P> <P>5.中文q问题:<BR>mysql 默认~码 iso<BR>tomcat request 传输~码 iso <BR>如果要显CZ?BR>?.jsp中添?BR><head><BR><%@ page <BR>language="java"<BR>contentType="text/html; charset=GB18030"<BR>pageEncoding="GB18030"<BR>%><BR></head><BR>如果是数据传输中的ؕ?如用servlet从mysql数据库读出的数据)<BR>用以下两个{码函数{?如果不清楚由哪种~码转成哪种~码,多试.<BR>    //转码GBK转ISO<BR>    public String toISO(String input) {<BR>        try {<BR>                byte[] bytes = input.getBytes("GBK");<BR>                return new String(bytes,"ISO8859-1");<BR>        }catch(Exception ex) {<BR>        }<BR>        return input;</P> <P>    }<BR>    <BR>    //转码IS0转GBK<BR>    public String toGBK(String input) {<BR>        try {<BR>            byte[] bytes = input.getBytes("ISO8859-1");<BR>            return new String(bytes,"GBK");<BR>        }catch(Exception ex) {<BR>        }<BR>        return input;<BR>    }</P> <P><BR>以上配置都测试通过.主要参考tomcat5.0的帮助文?过E写出来与大家共?如果发现其中错误,h?<BR>Ƣ迎l我来信<A href="mailto:ycg01@software.nju.edu.cn">ycg01@software.nju.edu.cn</A>共同探讨. </P><img src ="http://www.aygfsteel.com/lmsun/aggbug/10299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lmsun/" target="_blank">my java</a> 2005-08-17 09:38 <a href="http://www.aygfsteel.com/lmsun/articles/10299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ӽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ȷɽ</a>| <a href="http://" target="_blank">ƺ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɿ</a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˫</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">޶</a>| <a href="http://" target="_blank">пǰ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ĭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˷</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>