3/26/08


J2EE Security with WebLogic 9.2.1 Part 1. Web


First of all let us look into web application sequrity. Suppose we have some .war file with servlet com.MyServlet and web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Investigation_web</display-name>
<servlet>
<description></description>
<display-name>MyServlet</display-name>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.MyServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<security-role>
<description>This is the boss</description>
<role-name>manager</role-name>

</security-role>

<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>DELETE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
</web-resource-collection>

<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>

<login-config>
<auth-method>FORM</auth-method>
<realm-name>Example Form-Based Authentication Area</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login.jsp</form-error-page>
</form-login-config>
</login-config>

</web-app>

Also weblogic.xml contains:

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wls="http://www.bea.com/ns/weblogic/90" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">
<wls:context-root>Investigation_web</wls:context-root>
<wls:security-role-assignment>
<wls:role-name>manager</wls:role-name>
<wls:principal-name>alex</wls:principal-name>
</wls:security-role-assignment>
</wls:weblogic-web-app>


And in WebLogic Server console of our Domain we created user alex in default Realm. And finally there is login.jsp:

<form method="POST" action="j_security_check">
Username: <input type="text" value="weblogic" name="j_username"><br />
Password: <input type="password" value="weblogic" name="j_password"><br />
<br />
<input type="submit" value="Login">
<input type="reset" value="Reset">

</form>

So if user try to access MyServlet or any other resource that meets <url-pattern>/*</url-pattern> he will be redirected into login page. Also if use <auth-method>BASIC</auth-method> then no jsp login page is needed instead will be used popup window from your browser.
It is clear but what if we will try to acess URL in java standalone application's code? First of all I consider possibility of using HttpURLConnection as described in previous post of my blog. In that case we can fulfil:
1-request to login page and accept cookie;
2-post form with parameter names that we can find in login page HTML source (usual: username and password) with cookie;
3-request desired resource with cookie.

But it not seems the solution is simple. There is also Authenticator class to do similar job:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;

public class Main {


public static void main(String[] args) throws IOException {
Authenticator.setDefault(new SimpleAuthenticator("alex", "password"));
URL myUrl = new URL("http://localhost:7001/Investigation_web/MyServlet");
HttpURLConnection yc = (HttpURLConnection)myUrl.openConnection();
yc.setDoInput(true);
yc.setDoOutput(true);
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}


public static class SimpleAuthenticator extends Authenticator {
private String username;
private String password;
public SimpleAuthenticator(String username, String password) {
this.username = username;
this.password = password; }
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
}
}


But it approach useful only in case of BASIC auth-method. It is called "authenticate using the digest method". Might be we can use JAAS functionality? Pay attention that to run this code on Java 1.5 you have to add file sample_jaas.config that contains:

/** Login Configuration for the JAAS Sample Application **/
Sample { weblogic.security.auth.login.UsernamePasswordLoginModule required debug=false;};


and add line to java.security:

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

all those in directory: JAVA_HOME\jre\lib\security.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.PrivilegedAction;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.login.*;
import com.MyBeanRemoteHome;
import weblogic.security.Security;


public class Main {

public static void main(String[] args) throws Exception {
LoginContext loginContext = null;
loginContext = new LoginContext("Sample", new SampleCallbackHandler("alex", "weblogic", "t3://localhost:7001"));
loginContext.login();
Security.runAs(loginContext.getSubject(), new WebInvocation());
return;
}
public static class WebInvocation implements PrivilegedAction {
public Object run() {
URL myUrl;
try {
myUrl = new URL("http://localhost:7001/Investigation_web/MyServlet");
HttpURLConnection yc = null;
yc = (HttpURLConnection) myUrl.openConnection();
yc.setDoInput(true);
yc.setDoOutput(true);
BufferedReader in = new BufferedReader(new InputStreamReader(yc
.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}


No.. result is the same - we recieve redirect to login page in case of FORM auth-method and "Response: 401: Unauthorized" for BASIC. What about authenticate with certificates? For now nothing ). There is also question about why code to logout user:

request.getSession().invalidate();

does not work in case of BASIC authentication..

Next let's look into using URLConnection from some secured servlet to it themselves. Result of such invoking is the same as from standalone client: so in case of FORM authentication method request redirected to login page and in case of BASIC authentication method Response: '401: Unauthorized'. So the fact that invoking of some URL is doing from already authenticated code does not matter at all. The code have to tranfer cookie explicitly or use another method to authetication (Authenticator class and probably others). What about using url appending instead cookie? For now nothing again)

No comments: