I am still not pleased - Certain things are still missing, like the "originally requested URL" - making it impossible to do something like, allow a user to self-register and return to their original destination. I read that Oracle are working on the request, but who knows how long it will take with all the legitimate bugs out there.
OFM OAM SDK 11g
The 11g SDK is a simple Java API. Download and extract "ofm_oam_sdk_generic_11.1.1.5.0_disk1_1of1.zip" - no installer necessary. Sort of.
To get started, create a 10g gate in the OAM console, and copy the generated ObAccessClient.xml to your "AccessServerSDK" home folder within the subfolders: oblix\lib. For example, on my workstation, I created "C:\Oracle\asdk\oblix\lib".
From that point, you can copy the AccessServerSDK directory ("C:\Oracle\asdk") to setup multiple clients on developer or test machines, no worries, as long as the path is the same for everyone.
Add your oam-sdk jar to the project classpath - that's it. See Oracle API for a basic example or keep reading.
The fun part is using the SDK to authenticate a user for a valid SSO session they can take with them. I will get to that in a second, let's show the basic concept first.
Basic OAM SDK client class
Let's start with logging in with a basic OAM SDK client. To run this test, update: configLocation, login, password, resource for your environment.
You can use any http resource already protected in OAM, or create a new one with any FORM type Authentication Scheme.
The resource format is : "//HostnameFromHostIdentifier:80/ResourcePath"
In my environment, I need the code to work on Windows or Unix, so there are two configLocation values - use is determined by the java System Property for OS.
import java.util.Hashtable;
import oracle.security.am.asdk.AccessClient;
import oracle.security.am.asdk.AccessException;
import oracle.security.am.asdk.AuthenticationScheme;
import oracle.security.am.asdk.ResourceRequest;
import oracle.security.am.asdk.UserSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* To generate the Access SDK log, you must provide a logging configuration file
* when you start the application. e.g.
* java -Djava.util.logging.config.file=JRE_DIRECTORY/lib/logging.properties
*/
public class Simple10gClient {
protected static final Logger log = LoggerFactory.getLogger(Simple10gClient.class);
// assume all resources are http GETs
public static final String res_type = "http";
public static final String ms_method = "GET";
// Using standard location for SDK; will choose based on OS.
public static String configLocation = "/Oracle/Middleware/asdk";
public static String winConfigLocation = "C:/Oracle/asdk";
private static AccessClient ac;
private Simple10gClient() {}
// simple test
public static void main(String argv[]) {
String anonResource = "//AccessServerSDK_HostID:443/ResourceProtectedWithNoPasswordScheme";
String login = "testuser1";
String password = null;
try {
String sId = Simple10gClient.authenticate(anonResource, login, password);
Simple10gClient.isLoggedIn(sId);
Simple10gClient.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
private static void setupAccessClient() {
try {
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("win") > -1) {
configLocation = winConfigLocation;
}
// "C:/Oracle/asdk/oblix/lib/ObAccessClient.xml" must exist/be valid:
log.info("getAccessClient() config:" + configLocation );
ac = AccessClient.createDefaultInstance(configLocation , AccessClient.CompatibilityMode.OAM_10G);
log.info("Nap:" + AccessClient.getNAPVersion() + " SDK:" + AccessClient.getSDKVersion());
Hashtable diagnostic = ac.getServerDiagnosticInfo();
for (Object key : diagnostic.keySet()) {
log.info("Server Diagnostic " + key + "==" + diagnostic.get(key));
}
diagnostic = ac.getClientDiagnosticInfo();
for (Object key : diagnostic.keySet()) {
log.info("Client Diagnostic " + key + "==" + diagnostic.get(key));
}
} catch (AccessException ae) {
if (ae.getMessage().indexOf("OAMAGENT-02055") > -1) {
log.error("AccessServerSDK - is this agent webgate configured? " + ae);
} else {
log.error("Access Exception: " + ae.getMessage(), ae);
}
}
}
public static String authenticate(String resource, String login, String pw) {
log.debug("authenticate() user=" + login + " res:" + res_type + " " + resource);
try {
if (ac == null || !ac.isInitialized()) {
setupAccessClient();
}
ResourceRequest rrq = new ResourceRequest(res_type, resource, ms_method);
if (rrq.isProtected()) {
log.info("Resource is protected: " + resource);
AuthenticationScheme authnScheme = new AuthenticationScheme(rrq);
if (authnScheme.isForm()) {
log.info("Form Authentication Scheme: " + authnScheme.getName());
Hashtable creds = new Hashtable();
// to know credential key names, either you write the AuthN scheme yourself
// or go with the Oracle example.
creds.put("userid", login);
if (pw != null && pw.length() > 0)
creds.put("password", pw);
UserSession session = new UserSession(rrq, creds);
if (session.getStatus() == UserSession.LOGGEDIN) {
if (session.isAuthorized(rrq)) {
log.info("User is logged in and authorized, level " + session.getLevel());
} else {
log.info("User is logged in but NOT authorized");
}
log.info("User sessionToken:" + session.getSessionToken());
return session.getSessionToken();
} else {
log.warn("User is NOT logged in");
return null;
}
} else {
log.warn("non-Form Authentication Scheme.");
}
} else {
log.warn("Resource is NOT protected.");
}
} catch (AccessException ae) {
log.error("authenticate() Access Exception: " + ae.getMessage());
}
return null;
}
public static void logout(String sessionId) {
try {
if (ac == null || !ac.isInitialized()) {
setupAccessClient();
}
oracle.security.am.asdk.UserSession session = new UserSession(ac, sessionId);
log.info("is logout required? " + session);
if (session.getStatus() == 1)
session.logoff();
} catch (Exception ae) {
log.error("logout() Access Exception: " + ae.getMessage(), ae);
}
}
/**
* @param sessionId
*/
public static boolean isLoggedIn(String sessionId) {
// 0 for AWAITINGLOGIN
// 1 for LOGGEDIN
// 2 for LOGGEDOUT
// 3 for LOGINFAILED
// 4 for EXPIRED
try {
if (ac == null || !ac.isInitialized()) {
setupAccessClient();
}
oracle.security.am.asdk.UserSession session = new UserSession(ac, sessionId);
log.info("isLoggedIn startTime:" + session.getStartTime() + " status:" + session.getStatus());
java.util.Date since = new java.util.Date(session.getStartTime());
log.debug("since? " + since);
return session.getStatus() == 1;
} catch (Exception ae) {
log.error("isLoggedIn() Access Exception: " + ae.getMessage(), ae);
}
return false;
}
public static void shutdown() {
try {
if (ac != null)
ac.shutdown();
} catch (Exception e) {
log.warn("AccessServerSDK shutdown error " + e);
}
}
}
Right click and Run in eclipse, and you should see something like:
- authenticate() user=testuser1 resource:http //AccessServerSDK_HostID:443/ResourceProtectedWithNoPasswordScheme
- getAccessClient() config:C:/Oracle/asdk
- Nap:3 SDK:OAMAccessSDK_Ver_11.1.1.5
- Server Diagnostic oamserverhostname5575=={}
- Client Diagnostic oamserverhostname5575=={host=oamserverhostname, port=5575, priority=1, createtime=1326647958849}
- Resource is protected.
- Form Authentication Scheme.
- User is logged in and authorized for the request at level 3
- User sessionToken:LEHZ+zmSIZiamCTmHNQh9S+4JH0R8AvJ0eVwLPkUwmZArWb9qOg
KHYtEKrNTYHmEjt/UcqfFQ3Bq+mWud7APd0lqZlf31IigqrUAKJn7wRbRHanIpIQ1ygj64s
FjCoP6CwSTvSGeLY6gv49okJCM/2QivVqWb2Ce1Xwru89Vs/ZaE7YVXfjS8DnWwPBqYR8kQ
ONN348NI2cRMSMbryhG4neWah7rSFtJDH/gwAU55xwpE4SCcfTsXor8Qm7Ag==
Using the OAM SDK to authenticate a web client
My next step is wildly insecure, but a good shortcut for this example. Using the session ID generated with the SDK login, construct a valid SSO cookie and send the user on their merry authenticated way.
First, in the OAM console: Create a resource for your AccessServerSDK host, path "ResourceProtectedWithNoPasswordScheme" and add a "No Password Authentication Scheme" to it. I created my own AuthN scheme, setting the level to 3 - because I needed to match the authentication level of the forwarding online resource.
Create a LogMeIn servlet class taking a request parameter for login ID, and log the user in with a request parameter (see what I mean about being wildly insecure!):
String login = request.getParameter("login");
String anonResource = "//AccessServerSDK_HostID:443/ResourceProtectedWithNoPasswordScheme";
try {
String sessId = Simple10gClient.authenticate(anonResource, login, null);
log.info("Anon authenticate sessId:" + sessId);
// using the Session ID, create a ObSSOCookie and give it to the user
if (sessId != null) {
Cookie obCookie = new Cookie("ObSSOCookie", sessId);
obCookie.setDomain(".domain.com");
// obCookie.setHttpOnly(true); -- not sure why Weblogic 10.3.5 wasn't able to find this method
obCookie.setPath("/");
response.addCookie(obCookie);
// now send a response.redirect to a level 3 protected resource, user is logged in
}
} catch (Exception e) {
response.getOutputStream().print("Exception " + e);
log.error("logmein failed", e);
}
Deloying on the OIM/OAM WLS Domain
There was a bit of a gotcha using this sdk jar on the same domain as OIM/OAM - class/jar conflicts. Easily solved by adding a weblogic.xml to the war WEB-INF, requesting that weblogic look at the web libraries only.
<wls:container-descriptor>
<wls:prefer-application-packages>
<!-- add package names from the Oracle Access Server SDK -->
<wls:package-name>com.oblix.*</wls:package-name>
<wls:package-name>oracle.security.am.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
The end result of this is that you now can authenticate with standard username / password, check if the value of an ObSSOCookie is a valid session token, and generate for the end-user a valid SSO token to continue their with session on other OAM protected resources.
2 comments:
Hi,
Great post!
I have a question on your setup regarding the servlet example. Does your redirect go to a resource protected by a 10g or 11g WebGate?
In case of an 11g WebGate: Does it work with an obSSOCookie on your side?
Best regards,
B.
Good question - 10g webgate tested only - If you try 11g let me know.
Post a Comment