I find a pretty picture much more understandable than a great big blob of text. Part of it is that I'm more of a visual person and part of it is that I tend to get distracted easily. Plus if you're already familiar with OSSO or OAM 10g you probably already know what their cookies look like. So for the purposes of this post I'm only going talk about OAM 11g Server and the 11g WebGate cookies when you do an "HTML form" style login. Basically if you want the contents Eric's post in pretty pictures and simplified down to include only the 11g cookies then this post is for you! Here's a very simple diagram of the communication between the user, one OAM Server, one WebGate and one Application: Note: In this diagram I've separated out the WebGate and the Application, though in reality the WebGate is plugged into the OHS Server and the app could be something as simple as a .CGI running in the same server. I've also shown the user talking directly to the OAM Server; in the real world this interaction would likely be through an OHS server with mod_wl installed. Before we jump into the actual flows here's a little UML-ish sequence diagram for those of you that love those sorts of things: And the OAM docs have a GREAT diagram that covers the flow: When the user first attempts to access a protected resource the WebGate will detect that the resource is protected and that the user needs to be redirected to the OAM Server to login. The WebGate stores some information about the user's request, generates a cookie as a key to this context and sends an HTTP response with this cookie and the URL of the OAM Server. Here's a sample:
GET /protected/ HTTP/1.1 Host: idm11g.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive HTTP/1.1 302 Found Date: Sun, 10 Apr 2011 21:39:34 GMT Server: Oracle-Application-Server-11g Location: https://login.oracledemo.com/oam/server/obrareq.cgi?encquery%3DvAdYBjjl2VsVKd4BUocWvKLrTgh7O%2FulOsfaTcOtj%2FHCW0jI0WaKRY%2BUklaoED8x6IQ%2FtnktpR%2FNN2NvsLZJb3wTyUomlOxQgqX59aRla2LTQUIBsbO4Tw5PlFFsgDYdWoUUAA6HHTU4P1ZyloMzcbqn4mtXK6t5CAbOvEuB787m0VKOCPhvaO5OEibx5MEYtW1P0b1nqOeAlMUQdA6dg7BW8PbjgI7Ek3Esy4yJJN2EUBw90%2BjAJzLgQMUxtd%2FOc%2B6q60WFnZEMyRlmJW7moeoyPbMnookrb22WEd8pTsQ%3D%20agentid%3Didm11g%20ver%3D1 Content-Length: 608 Content-Type: text/html; charset=iso-8859-1 Set-Cookie: OAMAuthnCookie_idm11g.oracledemo.com:80=loggedoutcontinue;httponly; path=/; Set-Cookie: OAMRequestContext_idm11g.oracledemo.com:80_316f33=1o3lYFHrBi/OSAW5bGkEgA==; Expires=Sun, 10-Apr-2011 21:44:34 GMT; path=/; Connection: closeIf you look in the HTTP response above you'll see 2 Set-Cookie headers - one deleting OAMAuthnCookie_something (well setting it to loggedoutcontinue) and another named OAMRequestContext_something with a short key. Don't worry about the former for the moment; the latter is how the WebGate can get back to the original request later. The browser then follows the redirect and loads obrareq.cgi from the OAM Server. Despite the name obrareq.cgi isn't a CGI. The name is historical and we kept it for a few reasons, none of which really matter for this discussion. When the user requests obrareq.cgi the server responds with another redirect - this time to the HTML login form defined in the Authentication Scheme. Here's my Authentication Scheme configuration: and here's the HTTP transaction when the browser requests obrar.cgi:
GET /oam/server/obrareq.cgi?encquery%3DvAdYBjjl2VsVKd4BUocWvKLrTgh7O%2FulOsfaTcOtj%2FHCW0jI0WaKRY%2BUklaoED8x6IQ%2FtnktpR%2FNN2NvsLZJb3wTyUomlOxQgqX59aRla2LTQUIBsbO4Tw5PlFFsgDYdWoUUAA6HHTU4P1ZyloMzcbqn4mtXK6t5CAbOvEuB787m0VKOCPhvaO5OEibx5MEYtW1P0b1nqOeAlMUQdA6dg7BW8PbjgI7Ek3Esy4yJJN2EUBw90%2BjAJzLgQMUxtd%2FOc%2B6q60WFnZEMyRlmJW7moeoyPbMnookrb22WEd8pTsQ%3D%20agentid%3Didm11g%20ver%3D1 HTTP/1.1 Host: login.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive HTTP/1.1 302 Moved Temporarily Date: Sun, 10 Apr 2011 21:39:34 GMT Location: https://login.oracledemo.com/oam/pages/login.jsp?request_id=8909287934039423969 X-ORACLE-DMS-ECID: 11d1def534ea1be0:-4189cb25:12f40a0ec71:-8000-000000000000169c X-Powered-By: Servlet/2.5 JSP/2.1 Connection: close Transfer-Encoding: chunked Content-Type: text/plain; charset=UTF-8Notice the "?request_id=" and a key? When the user requests obrar.cgi the OAM Server squirrels away the request information and generates a short identifier to remember the user's request. The value of request_id is how the OAM Server gets back to the original request information when the user POSTs their credentials. Next, the user loads the login page (/oam/pages/login.jsp in this example).
GET /oam/pages/login.jsp?request_id=8909287934039423969 HTTP/1.1 Host: login.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive HTTP/1.1 200 OK Date: Sun, 10 Apr 2011 21:39:34 GMT Cache-Control: no-cache Pragma: no-cache Content-Length: 3201 Content-Type: text/html; charset=UTF-8 Expires: 0 X-ORACLE-DMS-ECID: 11d1def534ea1be0:-4189cb25:12f40a0ec71:-8000-000000000000169e X-Powered-By: Servlet/2.5 JSP/2.1 Connection: closeFinally! an HTTP 200 and we're done following redirects for a moment. This is the point where the user sees a login page. In this example I configured my Authentication Scheme to use the default JSP login page included with OAM. I'm sure you've seen it before, but that login page looks like this: OK, so the user enters the username and password and hits the Login button. The browser does an HTTP POST to /oam/server/auth_cred_submit. Like so:
POST /oam/server/auth_cred_submit HTTP/1.1 Host: login.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: https://login.oracledemo.com/oam/pages/login.jsp?request_id=8909287934039423969 Content-Type: application/x-www-form-urlencoded Content-Length: 66 username=testuser&password=ABcd1234&request_id=8909287934039423969 HTTP/1.1 302 Moved Temporarily Date: Sun, 10 Apr 2011 21:39:41 GMT Location: https://idm11g.oracledemo.com/obrar.cgi?encreply=aHRPbw8cp0LjIHx9Dd6DaT1kcHzmbIUudciQui%2F7lC52miYo77nRNh8JtH1UKeJ5O%2B12QyAcNlEES0TFZW7zQ%2FtCnh9PKFD%2B1y%2BGLYsEbnfHrsnqFmT4R%2F15b8kGdSyUP5TatLW6X4oAc9B2n9qPF3YBPlwHK7rRXMmhKleJa6X%2FjSWB%2Ff3YeWz1xrGidkvUXekC75Kldmu%2FL6O9jgbxk0tksCTjumZINMFOREUjrBFdCIGNDJlKiXeqBPMMccQXp5gg%2Fh5gT2s7wycJeAgyNxSH75%2FiYb9fC4tlo3aNB8bQ0ExpUSx8%2BTdOTf%2B1CpCv8Ue%2BESOoxEJYCVeQ248Omjmj%2B2UML0A%2F3KvWZjSHJY%2FTaleo3mzVG64lbdJGGsp8cXpbwK6MNZEtS6aDPdq4rgmNNAhnJ8bvmIUrlm3FfFp66anpYkvSUCORoaN991YwgZ5tOQ5p%2BZqN6O9qL5T7XUS7HWPwixEy0zH1CHDrQzmf0GaN9x4BfY3EdyGVQIh04Sf2V3Tf3r3cF4aW6xJuNMiu24kZYJ3tF8%2BjmdAmb3GoXtwOrCOUcSc%2FKV9%2F4oIBoZH6b5GW047VF5NGgNfM17I0J%2Fe1epQE2%2Bs0iLXlBu0IhFkaYiyDI2dl8CXohgeoTjOD74EeZFBcDMZHAYEVNjfZg2BuTNn7qaUTJkUztbM%3D X-ORACLE-DMS-ECID: 11d1def534ea1be0:-4189cb25:12f40a0ec71:-8000-00000000000016aa X-Powered-By: Servlet/2.5 JSP/2.1 Set-Cookie: OAM_ID=PvUkA907xd81Jv/P53npTW0JOSDTacc3jdGiL3tMB87z/RfZP91Bh2dQmM8v71rQTCZnJ1isOaQeJw8dSjfo7kXMFA8URsmL9uiszpOQYEH7SuvHVr1IjVRY3pPAlYhUrfLwEW5lvKMY9MF3KYTzvfuUJLMKZb0sc70KxdmXcnJrAFOSVMALhUEaUVOTZVI3aQCqEVmdnkh0QlSBkz9tsqxE0/VTacEnhPg2DlPxC9uKnElAsByo+8wczYlBemiyMR9g0BWasN+uR4TMo9pLtky/B0TmA43uOQuFvItW6twFJH3wSu6XofKo/Cy4bS0i; path=/; HttpOnly Connection: close Transfer-Encoding: chunked Content-Type: text/plain; charset=UTF-8The OAM Server validates the username and password ("testuser" and "ABcd1234" in this case) and since they're correct it generates an OAM_ID cookie. This is the first cookie we've seen so far that identifies the user! If you look carefully you'll notice a couple of interesting things about the cookie: The first is that it doesn't have a domain= setting; as a result the OAM_ID cookie will only be sent by the browser to the OAM Server; no WebGates will ever see the OAM_ID cookie. The second interesting thing to notice is that the cookie is marked "HttpOnly"; the HttpOnly marker tells the browser that the cookie should NOT be accessible to Javascript or browser plug-ins.
(note: in an earlier version of this post I accidentally said "host=" instead of "domain=". My apologies for the error!) The OAM Server redirects the user back to obrar.cgi (this time on the application) with encreply= and a big long encrypted string. The encreply that the OAM Server includes in that redirect contains enough information to allow the WebGate to pick up the user's session from the OAM Server. And so it does:
GET /obrar.cgi?encreply=aHRPbw8cp0LjIHx9Dd6DaT1kcHzmbIUudciQui%2F7lC52miYo77nRNh8JtH1UKeJ5O%2B12QyAcNlEES0TFZW7zQ%2FtCnh9PKFD%2B1y%2BGLYsEbnfHrsnqFmT4R%2F15b8kGdSyUP5TatLW6X4oAc9B2n9qPF3YBPlwHK7rRXMmhKleJa6X%2FjSWB%2Ff3YeWz1xrGidkvUXekC75Kldmu%2FL6O9jgbxk0tksCTjumZINMFOREUjrBFdCIGNDJlKiXeqBPMMccQXp5gg%2Fh5gT2s7wycJeAgyNxSH75%2FiYb9fC4tlo3aNB8bQ0ExpUSx8%2BTdOTf%2B1CpCv8Ue%2BESOoxEJYCVeQ248Omjmj%2B2UML0A%2F3KvWZjSHJY%2FTaleo3mzVG64lbdJGGsp8cXpbwK6MNZEtS6aDPdq4rgmNNAhnJ8bvmIUrlm3FfFp66anpYkvSUCORoaN991YwgZ5tOQ5p%2BZqN6O9qL5T7XUS7HWPwixEy0zH1CHDrQzmf0GaN9x4BfY3EdyGVQIh04Sf2V3Tf3r3cF4aW6xJuNMiu24kZYJ3tF8%2BjmdAmb3GoXtwOrCOUcSc%2FKV9%2F4oIBoZH6b5GW047VF5NGgNfM17I0J%2Fe1epQE2%2Bs0iLXlBu0IhFkaYiyDI2dl8CXohgeoTjOD74EeZFBcDMZHAYEVNjfZg2BuTNn7qaUTJkUztbM%3D HTTP/1.1 Host: idm11g.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: https://login.oracledemo.com/oam/pages/login.jsp?request_id=8909287934039423969 Cookie: OAMAuthnCookie_idm11g.oracledemo.com:80=loggedoutcontinue; OAMRequestContext_idm11g.oracledemo.com:80_316f33=1o3lYFHrBi/OSAW5bGkEgA== HTTP/1.1 302 Found Date: Sun, 10 Apr 2011 21:39:41 GMT Server: Oracle-Application-Server-11g Location: /protected/ Content-Length: 209 Content-Type: text/html; charset=iso-8859-1 Set-Cookie: OAMRequestContext_idm11g.oracledemo.com:80_316f33=; Expires=Thursday, 01-Jan-1970 01:00:00 GMT; path=/; Set-Cookie: OAMAuthnCookie_idm11g.oracledemo.com:80=BSMcTDP6bI93Nv7mrpH77ESezwe9OJJEvlB3Y7Bir3%2FrcwvB8j8xZj2tc0mzQKUJYfNEjnRB%2BJWg3EQw%2BAei51dq7IhVJQ4xZhfv9eKqB1f0BMwc%2BOMt9ADJ7wZ47rGqEp85DYTRIeXPE6wMSJMkRFIvEzh2zKmeZoBv7x2G2DsepKXwAsgv2OZqmXvISu4gzDweUbcY6N8%2B4KuYAqCd1FAHO6aMKlj6ak05cdAVtzGXBcc3y%2FdRW1Yhjer9oZEBBcW73e9uhrfwOq6lZHE0BHoPZT5YWrXQRUJH3VBxj7gPAMQASwQh6wUyvvC%2BN4Zm;httponly; path=/; Connection: closeThis is the second cookie we've seen that identifies the user. Again, this cookie is host-specific and HttpOnly. There's another interesting thing about the cookie - notice the cookie name "OAMAuthnCookie_idm11g.oracledemo.com:80"? The WebGate figures out the cookie name automatically. The user follows the redirect back to the original resource - /protected/.
GET /protected/ HTTP/1.1 Host: idm11g.oracledemo.com User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.18) Gecko/2010021717 Oracle/3.0.18-1.0.1.el5_4 Firefox/3.0.18 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: https://login.oracledemo.com/oam/pages/login.jsp?request_id=8909287934039423969 Cookie: OAMAuthnCookie_idm11g.oracledemo.com:80=bQ%2Bx9MCKyEjON3nOt5d7niWgbSEksG4qCEPaGF82blgf76HBAgmnEy3gkGoPzTBs8Ac1zTBNSnvHS8EmubYuZR0I4spgrchEtuuKdKJHPkWXQg9S1RRoycAys%2F8GDa6rRbvWJNRFc11yfK0X3g3Buxb6MvpDmsEGraleqKtdBSjtRG1PS8zl4Mijd7Tu1a3NFMgONgdoHKnoNyF3T13HjFbILIvLVuTdjE6t9EyomX4XXijXxqUZtTrZB%2BjRzy3jVLUeKKHhcNn7CTZrKhMJYtDVd8Z4d34vyyGgE%2BlJd%2BdkKGQr1sstpfpVVlyivvo4 HTTP/1.1 200 OK Date: Sun, 10 Apr 2011 21:39:41 GMT Server: Oracle-Application-Server-11g Cache-Control: no-cache Pragma: no-cache Content-Type: text/html; charset=ISO-8859-1 Content-Language: en Connection: close Transfer-Encoding: chunkedSo a quick summary:
- The OAM Server gets and sets a cookie named OAM_ID.
- Each WebGate gets and sets a cookie named OAMAuthnCookie_ + the host name and port.
the contents of the cookies are:Eric also mentioned that the 11g OAMAuthnCookie is encrypted with a key that is specific to the Webgate that issued the cookie. That means that if someone somehow compromises one web server and gets a copy of the OAMAuthnCookie for that server it isn't useable on any other web server and WebGate. One other note: Because the OAMAuthnCookie is a "per host" cookie and the only communication channel in the redirects is the obrar.cgi URL single sign on works across domain names. So in my case I have both the OAM Server and the application in .oracledemo.com, but I could just as easily have them in two completely different domains. Like oracle.com and oracleateam.com. In the next post I'm going to talk about how logout works so stay tuned!These cookies are updated periodically using an algorithm of 1/4 of idle session timeout. There are two main differences between the 10g and 11g cookies:
- Authenticated User Identity (User DN)
- Authentication Level
- IP Address
- SessionID (Reference to Server side session – OAM11g Only)
- Session Validity (Start Time, Refresh Time)
- Session InActivity Timeouts (Global Inactivity, Max Inactivity)
- Validation Hash
Thanks for the post Chris, But do you know if somebody gets hold of the OAM_ID Cookie by standing up a roque server as a sub domain in the access server domain, then that cookie could be used to gain access to all the SSO URLs which the user has access to? Is that a right statement. Lets assume that we do not capture IP information within the OAM_ID cookies for this discussion. Your response is greatly appreciated.
ReplyDeleteSrini
@Srinivas All of the OAM 11g cookies including OAM_ID are host specific cookies; that is to say the OAM_ID cookie will ONLY ever be sent from the browser to the OAM server itself. Plus it's marked as HttpOnly, so it's not even accessible via JavaScript or to a browser plug-in.
ReplyDeleteHi Chris,
ReplyDeleteThat was a wonderful post. I just have a quick question. You mentioned in the post that OAM_ID cookie does not have host=setting. Does this mean that it is not host specific?
Thanks,
Mahendra.
Mahendra,
ReplyDeleteI think Chris meant to say that the OAM_ID cookie doesn't have a domain=setting. This means that the cookie IS host specific and will only be sent from the browser back to the OAM server.
--Brian
Hi Chris, thanks for your greate post.
ReplyDeleteIs there any way to generate authentication token in Java Code, which used to create OAMAuthnCookie with OAM 11g(11.1.1.5.0) API?
I had used OAM 10g SDK to create ObSSOCookie in OAM 10g Env, now I want do the similar thing in OAM 11g Env, however, I can only fetch user session token from UserSession object without authentication token. Can you give some suggestions?
Best withes!
eleven
eleven,
ReplyDeleteThere is a call in the OAM 11g SDK to generate a token, but that token is not an OAM_ID cookie and it's not an OAM_AuthN cookie. It is an old school 10g style cookie which OAM 11g WebGates and the OAM server will not accept. Basically it's been included in the SDK for backwards compatibility.
You should look at the Authentication Plug-in interface if you want to hook into the session creation process. I'll have a post on that in the near(ish) future.
Hi Chris - more really useful info here! One thing that puzzles me still though is how to pass the target URL (of a protected resource) to a 'landing page' defined as the authentication success URL. It seems to me that the policy response is evaluated after the Success URL is set as it is this value that is set in the res_url variable and not the requested URL. I'm wondering if this is a 'feature' of 11.1.1.5?
ReplyDeleteRegards,
Bernie
Bernie: I'm not sure I follow. Can you email me directly please? Christopher dot Johnson at you know where dot com.
ReplyDeleteA very nice post indeed. But I have a question related to the third diagram (showing the data flow between user agent / webgate / oam server ).
ReplyDeleteQuestion : Shouldnt the user be redirected for authentication, in case the requested resource is protected, at end of Step 4 when the policy decision is sent to webgate by oam server.
If no than does the OAM server somehow sends some custom response in step 2 to Webgate which redirects the User Agent for authentication , and OAM server sends the Policy Decision separately to Webgate in step 4.
Regards
Yogesh
Yogesh: You are right - if I were using my own login page and hosting it on another server there would be a 302 after the first time I hit the OAM server. That 302 would redirect me to the login page wherever it lived.
ReplyDeleteBut since I'm using the default internal login page the OAM server does an internal request forward - saving one HTTP round trip. If you deploy your login page to the OAM server (and set the scheme up the right way) then OAM will do the same for your login page.
Excellent post Chris! We're actually using OAM in our application and one thing I've never understood completely is how the session information gets handed of to our application. All I know is that we have CLIENT-CERT as one of our authentication methods. Don't get me wrong, it is working great but I'd prefer if I actually knew how it works! :D
ReplyDeleteHi CHris, this is definitely a great post which helps me understand how OAM works.
ReplyDeleteBut i'm still confuse on the two redirect "cgi",
The first one "login.oracledemo.com/oam/server/obrareq.cgi", it will redirect user to the login page, this is running on the OAM server.
But for the second idm11g.oracledemo.com/obrar.cgi which belongs to application domain "idm11g.oracledemo.com", it is not a component of OAM server right?
Which means developer has to create such a component?
No, the obrar and obrareq components are part of the WebGate and OAM server respectively. The "CGI" in the name there is an artifact of a (much!) older version of the product.
ReplyDeleteHi Chris, great post. I'm trying to create a protected jsp that can display the cookies and http headers it receives. I'm able to display the jsessionid but the OAMAuthnCookie does not show up. I'm using request.getCookies(). I have verified that the cookie is sent in the request using Live HTTP Headers. Any ideas?
ReplyDeleteYou won't actually see the cookie in anything running behind a WebGate.
ReplyDeleteThe WebGate reads the incoming HTTP request, processes the OAMAuthN cookie, and then rebuilds the inbound Cookie header to filter out any OAMAuthN cookies. It does this security reasons - to prevent an application running on the web server or app server from being able to grab a cookie and potentially reuse it.