Retrieving the JWT token from WSO2 IS using SSO OIDC authentication protocol - node.js

I am implementing a basic NodeJS app that connects to WSO2 Identity Server for authentication.
I configured it using SSO with openid-connect. When I receive the callback, the jwt token is returned as a fragment identifier as I think it is returned as a GET request. How do I retrieve this JWT from the server side itself?
This is how the URL looks like when I try to login
https://localhost:9443/oauth2/authorize?response_type=id_token&client_id={CLIENT_ID}&scope=openid%20profile%20email&nonce=aaa&redirect_uri=http://localhost:3001/auth/callback
replaced the client_id with the actual client_id from what the Service Provider gave
this is a sample of how WSO2 returns the callback.
http://localhost:3001/auth/callback#id_token={TOKEN}

If you are using JAVA for your back-end development you can use a servlet filter to intercept this JWT token and process it. Following is a sample filter that you can use. You can use WSO2 Application Server to deploy your application.
public class JWTAction implements Filter {
private static final Logger logger = Logger.getLogger(JWTAction.class);
private static final PropertyReader propertyReader = new PropertyReader();
/**
* This method is for get public key
*
* #return return for getting public key
* #throws IOException if unable to load the file
* #throws KeyStoreException if unable to get instance
* #throws CertificateException if unable to certify
* #throws NoSuchAlgorithmException cause by other underlying exceptions(KeyStoreException)
*/
private static PublicKey getPublicKey() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
InputStream file = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(propertyReader.getSsoKeyStoreName());
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
//loading key store with password
keystore.load(file, propertyReader.getSsoKeyStorePassword().toCharArray());
Certificate cert = keystore.getCertificate(propertyReader.getSsoCertAlias());
return cert.getPublicKey();
}
public void init(FilterConfig filterConfig) {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String jwt = request.getHeader("X-JWT-Assertion");
String ssoRedirectUrl = propertyReader.getSsoRedirectUrl();
if (jwt == null || "".equals(jwt)) {
if (logger.isDebugEnabled()) {
logger.debug("Redirecting to {}");
}
response.sendRedirect(ssoRedirectUrl);
return;
}
String username = null;
String roles = null;
try {
SignedJWT signedJWT = SignedJWT.parse(jwt);
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) getPublicKey());
if (signedJWT.verify(verifier)) {
if (logger.isDebugEnabled()) {
logger.debug("JWT validation success for token: {}");
}
username = signedJWT.getJWTClaimsSet().getClaim("http://wso2.org/claims/emailaddress").toString();
roles = signedJWT.getJWTClaimsSet().getClaim("http://wso2.org/claims/role").toString();
if (logger.isDebugEnabled()) {
logger.debug("User = {" + username + "} | Roles = " + roles);
}
} else {
logger.error("JWT validation failed for token: {" + jwt + "}");
response.sendRedirect(ssoRedirectUrl);
return;
}
} catch (ParseException e) {
logger.error("Parsing JWT token failed");
} catch (JOSEException e) {
logger.error("Verification of jwt failed");
} catch (Exception e) {
logger.error("Failed to validate the jwt {" + jwt + "}");
}
if (username != null && roles != null) {
request.getSession().setAttribute("user", username);
request.getSession().setAttribute("roles", roles);
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} catch (ServletException e) {
logger.error("Failed to pass the request, response objects through filters", e);
}
}
public void destroy() {
}
}

Related

How to pass Authorization token from one webapi to other webapi?

I have configured two applications in Azure AD. One is a Web API called app-A and another is a Web API called app-B.
how to I generate a token at app-A using client credentials token
and pass that token to app-B?
If I understand your question correct you want to forward Authorization token from one Web API service to another Web API?
This is how I did it:
Create a session context that exists within the request context. This is done by using Unity and HierarchicalLifetimeManager.
Extract all headers from the request at app-a and put it into the session context
Using the HttpClient to insert the cookies before calling app-b.
If you want to, you could also just extract the token only instead of all cookies.
SessionContext
public class SessionContext
{
public string Token { get; private set; }
public CookieHeaderValue Cookies { get; private set; }
public void SetToken(string token)
{
if(Token != null)
throw new InvalidOperationException("Token is already set in this session.");
Token = token;
}
public void SetCookies(CookieHeaderValue cookies)
{
if (Cookies != null)
throw new InvalidOperationException("Cookies is already set in this session.");
Cookies = cookies;
}
}
CookieFetcher
/// <summary> ActionFilter to extract all cookie and add it to the <see cref="SessionContext"/>. </summary>
public class CookieFetcherAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var cookies = actionContext.Request.Headers.GetCookies().SingleOrDefault();
if (cookies == null)
return;
var sessionContext = actionContext.Request.GetDependencyScope().GetService<SessionContext>();
sessionContext.SetCookies(cookies);
}
}
Unity config
// Gets a new TokenProvider per request
container.RegisterType<SessionContext>(new HierarchicalLifetimeManager());
Client
public class Client
{
private CookieHeaderValue Cookies => sessionContext.Cookies;
public Client(SessionContext sessionContext)
{
this.sessionContext = sessionContext;
}
private HttpClient CreateHttpClient()
{
// If cookie/sessionId based authentication is used.
if (Cookies != null)
{
handler.CookieContainer = ConvertToCookieContainer(Cookies, baseUri.GetRootHostName());
handler.UseCookies = true;
}
var client = new HttpClient(handler, true);
client.BaseAddress = baseUri;
return client;
}
private static CookieContainer ConvertToCookieContainer(CookieHeaderValue cookies, string cookiePath)
{
var container = new CookieContainer();
foreach (var cookie in cookies.Cookies)
{
container.Add(new Cookie(cookie.Name, cookie.Value, "/", cookiePath));
}
return container;
}
}

How can I integrate SSO authentication with JSF?

I'm currently using a Filter to check for SSO authentication. (SSO is considered authenticated if the request header contains the variable "Proxy-Remote-User").
if (!(isSsoLoggedIn(request)) {
response.sendRedirect(ERROR_PAGE);
return;
} else {
chain.doFilter(req, res);
}
private boolean isSsoLoggedIn(HttpServletRequest request) {
return request != null && request.getHeader("Proxy-Remote-User") != null
&& !request.getHeader("Proxy-Remote-User").equals("");
}
Now, once the user is authenticated, I want to pass that variable (which is an email address) to JSF. I do that with a session-scoped bean:
#PostConstruct
public void init {
Map<String, String> requestHeaderMap = FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderMap();
String email = requestHeaderMap.get("Proxy-Remote-User");
user = getPersonFromDB(email);
}
This seems simple enough, but I'm not sure if its the "right" way to do this. It doesn't seem correct to rely on a bean's instantiation to verify authentication.
One idea I just had: Use a CDI session-scoped bean and #Inject it into the Filter. Then, you could have the filter itself check for a valid user and, if valid, set it in the session-scoped bean, otherwise forward it to an error page.
Does that sound like a valid solution?
Another approach could be to have every page check for authentication, before the view is rendered, with a view param as mentioned here:
JSF calls methods when managed bean constructor sends 404 ERROR CODE
<f:metadata>
<f:viewAction action="#{bean.checkForValidUser}" />
</f:metadata>
The only problem I have for this is...this would require copying/pasting the same code to every page which seems redundant (or at least a template for them all to use).
Here is the answer I came up with (thanks to some tips from #BalusC).
I check to see if developer login is enabled or SSO has been authenticated. Once I have the email address, I see if its a valid user, verify the JSF session contains the right user, and, if so, forward them on their way.
/**
* This filter handles SSO login (or developer login) privileges to the web
* application.
*/
#WebFilter(servletNames = "Faces Servlet")
public class SecurityFilter implements Filter {
#Inject
private SessionManager sessionManager;
#EJB
private PersonWriteFacadeRemote personFacade;
private HttpServletRequest currentRequest;
private HttpServletResponse currentResponse;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
currentRequest = (HttpServletRequest) req;
currentResponse = (HttpServletResponse) res;
HttpSession session = currentRequest.getSession();
String requestedPage = currentRequest.getRequestURI();
// check if the session is initialized
// if not, initialize it
if (!isSessionInitialized()) {
Person user = getCurrentUser();
// if we can't figure out who the user is, then send 401 error
if (user != null) {
initializeSession(user);
} else {
currentResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// if it is initialized, check if it actually matches the current
// user
// if not, invalidate the session and redirect them back to the page
// to reinitialize it
} else if (!isSessionCurrentUsers()) {
session.invalidate();
currentResponse.sendRedirect(requestedPage);
return;
}
chain.doFilter(req, res); // If all looks good, continue the request
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
private Person getCurrentUser() {
try {
return personFacade.createFromEmail(getUserEmail());
} catch (InvalidAttributesException ex) {
Logger.getLogger(SecurityFilter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
private String getUserEmail() {
return isDevLoginEnabled() ? getUserEmailFromJndi() : getUserEmailFromSso();
}
private String getUserEmailFromJndi() {
return JNDI.lookup("devLoginEmail");
}
private String getUserEmailFromSso() {
return currentRequest != null && currentRequest.getHeader("Proxy-Remote-User") != null
&& !currentRequest.getHeader("Proxy-Remote-User").equals("")
? currentRequest.getHeader("Proxy-Remote-User") : null;
}
private boolean isDevLoginEnabled() {
Boolean devLoginEnabled = JNDI.lookup("devLoginEnabled");
return (devLoginEnabled != null ? devLoginEnabled : false);
}
private boolean isSessionInitialized() {
return sessionManager.getUser() != null;
}
private void initializeSession(Person user) {
sessionManager.initializeSession(user);
}
private boolean isSessionCurrentUsers() {
return sessionManager.getUser() != null && sessionManager.getUser().getEmail() != null
&& sessionManager.getUser().getEmail().equals(getUserEmail());
}
}

J2ME http post error - Nokia Asha SDK 1.0

I am making a http-post request from my J2ME app for Nokia Asha 501(s40). I'm using the Nokia Asha SDK 1.0 for development.
Once the app tries to make http connection it goes directly into the finally clause of try-catch statement without throwing any exceptions.
In the emulator, the following message is displayed - "Something went wrong with running this app" - Screenshot-link
I then tried the sample http-post source code given in the Nokia developer forum and got the same result.
The code is given below.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class HttpPOST extends MIDlet implements CommandListener {
private static String defaultURL = "http://localhost/api/signin";
private Display myDisplay = null;
private Form mainScreen;
private TextField requestField;
private Form resultScreen;
private StringItem resultField;
Command sendCommand = new Command("SEND", Command.OK, 1);
Command backCommand = new Command("BACK", Command.OK, 1);
public HttpPOST()
{
myDisplay = Display.getDisplay(this);
mainScreen = new Form("Type in a URL:");
requestField = new TextField(null, defaultURL, 100, TextField.URL);
mainScreen.append(requestField);
mainScreen.addCommand(sendCommand);
mainScreen.setCommandListener(this);
}
public void startApp() {myDisplay.setCurrent(mainScreen);}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s)
{
if (c == sendCommand)
{
String urlstring = requestField.getString();
String resultstring = sendPostRequest(urlstring);
resultScreen = new Form("POST Result:");
resultField = new StringItem(null, resultstring);
resultScreen.append(resultField);
resultScreen.addCommand(backCommand);
resultScreen.setCommandListener(this);
myDisplay.setCurrent(resultScreen);
}
else if (c == backCommand)
{
requestField.setString(defaultURL);
myDisplay.setCurrent(mainScreen);
}
}
public String sendPostRequest(String urlstring)
{
HttpConnection hc = null;
DataInputStream dis = null;
DataOutputStream dos = null;
String message = "";
String requeststring = "email=test#gmail.com&password=1234";
try
{
hc = (HttpConnection) Connector.open(urlstring, Connector.READ_WRITE);
hc.setRequestMethod(HttpConnection.POST);
dos = hc.openDataOutputStream();
byte[] request_body = requeststring.getBytes();
for (int i = 0; i < request_body.length; i++)
{
dos.writeByte(request_body[i]);
}
// flush outdos.flush();
dis = new DataInputStream(hc.openInputStream());
int ch;
while ((ch = dis.read()) != -1)
{
message = message + (char) ch;
}
}
catch (IOException ioe)
{
message = "ERROR";
}
finally
{
try
{
if (hc != null)
hc.close();
}
catch (IOException ignored)
{
}
try
{
if (dis != null)
dis.close();
}
catch (IOException ignored)
{
}
try
{
if (dos != null)
dos.close();
}
catch (IOException ignored)
{
}
}
return message;
}
}
Somebody please help me out in solving this issue.
Thanks in advance.
Please find below an example. It will helpful to somebody. It is tested in Nokia Asha 501, It is perfectly working.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class GetNpost extends MIDlet implements CommandListener
{
private Display display; // Reference to Display object
private Form fmMain; // The main form
private Alert alError; // Alert to error message
private Command cmGET; // Request method GET
private Command cmPOST; // Request method Post
private Command cmExit; // Command to exit the MIDlet
private TextField tfAcct; // Get account number
private TextField tfPwd; // Get password
private StringItem siBalance;// Show account balance
private String errorMsg = null;
GetNetworkConnection getObject = null;
PostNetworkConnection postObject = null;
GetNpost mainObject = null;
public GetNpost()
{
display = Display.getDisplay(this);
mainObject = this;
// Create commands
cmGET = new Command("GET", Command.SCREEN, 2);
cmPOST = new Command("POST", Command.SCREEN, 3);
cmExit = new Command("Exit", Command.EXIT, 1);
// Textfields
tfAcct = new TextField("Account:", "", 5, TextField.NUMERIC);
tfPwd = new TextField("Password:", "", 10, TextField.ANY | TextField.PASSWORD);
// Balance string item
siBalance = new StringItem("Balance: $", "");
// Create Form, add commands & componenets, listen for events
fmMain = new Form("Account Information");
fmMain.addCommand(cmExit);
fmMain.addCommand(cmGET);
fmMain.addCommand(cmPOST);
fmMain.append(tfAcct);
fmMain.append(tfPwd);
fmMain.append(siBalance);
fmMain.setCommandListener(this);
}
public void startApp()
{
display.setCurrent(fmMain);
}
public void pauseApp()
{ }
public void destroyApp(boolean unconditional)
{ }
public void commandAction(Command c, Displayable s)
{
if (c == cmGET || c == cmPOST)
{
try
{
if (c == cmGET){
getObject = new GetNetworkConnection();
getObject.start();
}
else{
postObject = new PostNetworkConnection();
postObject.start();
}
}
catch (Exception e)
{
System.err.println("Msg: " + e.toString());
}
}
else if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
}
/*--------------------------------------------------
* Access servlet using GET
*-------------------------------------------------*/
private void lookupBalance_withGET() throws IOException
{
HttpConnection http = null;
InputStream iStrm = null;
boolean ret = false;
// Data is passed at the end of url for GET
// don't use localhost as a ip
String url = "http://(ip address):(port)/ServerSide/hello" + "?" +
"account=" + tfAcct.getString() + "&" +
"password=" + tfPwd.getString();
try
{
http = (HttpConnection) Connector.open(url);
//----------------
// Client Request
//----------------
// 1) Send request method
http.setRequestMethod(HttpConnection.GET);
// 2) Send header information - none
// 3) Send body/data - data is at the end of URL
//----------------
// Server Response
//----------------
iStrm = http.openInputStream();
// Three steps are processed in this method call
ret = processServerResponse(http, iStrm);
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
if (http != null)
http.close();
}
// Process request failed, show alert
if (ret == false)
showAlert(errorMsg);
}
/*--------------------------------------------------
* Access servlet using POST
*-------------------------------------------------*/
private void lookupBalance_withPOST() throws IOException
{
HttpConnection http = null;
OutputStream oStrm = null;
InputStream iStrm = null;
boolean ret = false;
// Data is passed as a separate stream for POST (below)
// don't use localhost as a ip
String url = "http://(ip address):(port)/ServerSide/hello";
try
{
http = (HttpConnection) Connector.open(url);
//----------------
// Client Request
//----------------
// 1) Send request type
http.setRequestMethod(HttpConnection.POST);
// 2) Send header information. Required for POST to work!
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
oStrm = http.openOutputStream();
// If you experience connection/IO problems, try
// removing the comment from the following line
// http.setRequestProperty("Connection", "close");
// 3) Send data/body
// Write account number
byte data[] = ("account=" + tfAcct.getString()).getBytes();
oStrm.write(data);
// Write password
data = ("&password=" + tfPwd.getString()).getBytes();
oStrm.write(data);
// For 1.0.3 remove flush command
// See the note at the bottom of this file
// oStrm.flush();
//----------------
// Server Response
//----------------
iStrm = http.openInputStream();
// Three steps are processed in this method call
ret = processServerResponse(http, iStrm);
}
catch(Exception e){
System.out.println("Error in Post: "+e.getMessage());
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
if (oStrm != null)
oStrm.close();
if (http != null)
http.close();
}
// Process request failed, show alert
if (ret == false)
showAlert(errorMsg);
}
/*--------------------------------------------------
* Process a response from a server
*-------------------------------------------------*/
private boolean processServerResponse(HttpConnection http, InputStream iStrm) throws IOException
{
//Reset error message
errorMsg = null;
// 1) Get status Line
if (http.getResponseCode() == HttpConnection.HTTP_OK)
{
// 2) Get header information - none
// 3) Get body (data)
int length = (int) http.getLength();
String str;
if (length != -1)
{
byte servletData[] = new byte[length];
iStrm.read(servletData);
str = new String(servletData);
}
else // Length not available...
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = iStrm.read()) != -1)
bStrm.write(ch);
str = new String(bStrm.toByteArray());
bStrm.close();
}
// Update the string item on the display
siBalance.setText(str);
return true;
}
else
// Use message from the servlet
errorMsg = new String( http.getResponseMessage());
return false;
}
/*--------------------------------------------------
* Show an Alert
*-------------------------------------------------*/
private void showAlert(String msg)
{
// Create Alert, use message returned from servlet
alError = new Alert("Error", msg, null, AlertType.ERROR);
// Set Alert to type Modal
alError.setTimeout(Alert.FOREVER);
// Display the Alert. Once dismissed, display the form
display.setCurrent(alError, fmMain);
}
public class GetNetworkConnection extends Thread{
public void run(){
try {
mainObject.lookupBalance_withGET();
}
catch(Exception e){
System.out.println("Error in Get Connection: "+e.getMessage());
}
}
}
public class PostNetworkConnection extends Thread{
public void run(){
try {
mainObject.lookupBalance_withPOST();
}
catch(Exception e){
System.out.println("Error in Post Connection: "+e.getMessage());
}
}
}
}
The server side code is, (It is a servlet. Name is hello.java)
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* #author thirumalvalavan
*/
#WebServlet(name = "hello", urlPatterns = {"/hello"})
public class hello extends HttpServlet {
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
// /*TODO output your page here
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet hello at " + request.getContextPath() + "</h1>");
out.println("</body>");
out.println("</html>");
// */
} finally {
out.close();
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// processRequest(request, response);
String acct = request.getParameter("account"),
pwd = request.getParameter("password");
System.out.println("Hello Get Method::: " + acct + " " + pwd);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.print("<h1>Hi Get Method: </h1> <br> <h2> Your Account is: " + acct + "<br> Your pwd is: " + pwd + "</h2>");
out.println("</body>");
out.println("</html>");
out.close();
}
/**
* Handles the HTTP <code>POST</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// processRequest(request, response);
String acct = request.getParameter("account"),
pwd = request.getParameter("password");
System.out.println("Hello Post Method::: " + acct + " " + pwd);
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.print("<h1>Hi Post Method: </h1> <br> <h2> Your Account is: " + acct + "<br> Your pwd is: " + pwd + "</h2>");
out.println("</body>");
out.println("</html>");
out.close();
}
/**
* Returns a short description of the servlet.
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}

ServiceStack and FacebookAuthProvider

I've been working with ServiceStack and it's Auth providers. Specifically "FacebookAuthProvider".
My issue here is that the service is called from an iOS app. This app already have a valid access token and i just want to pass this value to servicestack facebook authentication.
I've seen the tests on servicestack github page, but it still doesn't make sense to me.
Is it possible to pass this access token to servicestack, so the authentication skips the part where i ask for permission, since we already did the on the app?
Or am i approching this the wrong way?
Instead of using the builtin facebook auth provider i created my own CustomFacebookAuthProvider.
The reason is that the builtin version needs a browser to redirect the user to facebook for authentication and i didn't need that. I already had an access token.
So based on the official version FacebookAuthProvider.cs i created my own.
using System;
using System.Collections.Generic;
using System.Net;
using Elmah;
using Mondohunter.Backend.BusinessLogic.Interfaces;
using ServiceStack.Common.Extensions;
using ServiceStack.Common.Web;
using ServiceStack.Configuration;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Auth;
using ServiceStack.Text;
using ServiceStack.WebHost.Endpoints;
namespace Mondohunter.Interfaces
{
public class CustomFacebookAuthProvider : OAuthProvider
{
public const string Name = "facebook";
public static string Realm = "https://graph.facebook.com/";
public static string PreAuthUrl = "https://www.facebook.com/dialog/oauth";
public string AppId { get; set; }
public string AppSecret { get; set; }
public string[] Permissions { get; set; }
public CustomFacebookAuthProvider(IResourceManager appSettings)
: base(appSettings, Realm, Name, "AppId", "AppSecret")
{
this.AppId = appSettings.GetString("oauth.facebook.AppId");
this.AppSecret = appSettings.GetString("oauth.facebook.AppSecret");
}
public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
{
var tokens = Init(authService, ref session, request);
try
{
if (request.oauth_token.IsNullOrEmpty())
throw new Exception();
tokens.AccessToken = request.oauth_token;
session.IsAuthenticated = true;
var json = AuthHttpGateway.DownloadFacebookUserInfo(request.oauth_token);
var authInfo = JsonSerializer.DeserializeFromString<Dictionary<string, string>>(json);
//Here i need to update/set userauth id to the email
//UpdateUserAuthId(session, authInfo["email"]);
authService.SaveSession(session, SessionExpiry);
OnAuthenticated(authService, session, tokens, authInfo);
//return json/xml/... response;
}
catch (WebException ex)
{
//return json/xml/... response;
}
catch (Exception ex)
{
//return json/xml/... response;
}
}
protected override void LoadUserAuthInfo(AuthUserSession userSession, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
if (authInfo.ContainsKey("id"))
tokens.UserId = authInfo.GetValueOrDefault("id");
if (authInfo.ContainsKey("name"))
tokens.DisplayName = authInfo.GetValueOrDefault("name");
if (authInfo.ContainsKey("first_name"))
tokens.FirstName = authInfo.GetValueOrDefault("first_name");
if (authInfo.ContainsKey("last_name"))
tokens.LastName = authInfo.GetValueOrDefault("last_name");
if (authInfo.ContainsKey("email"))
tokens.Email = authInfo.GetValueOrDefault("email");
if (authInfo.ContainsKey("gender"))
tokens.Gender = authInfo.GetValueOrDefault("gender");
if (authInfo.ContainsKey("timezone"))
tokens.TimeZone = authInfo.GetValueOrDefault("timezone");
LoadUserOAuthProvider(userSession, tokens);
}
public override void LoadUserOAuthProvider(IAuthSession authSession, IOAuthTokens tokens)
{
var userSession = authSession as CustomUserSession;
if (userSession == null) return;
userSession.Email = tokens.Email ?? userSession.PrimaryEmail ?? userSession.Email;
}
}
}
I hope it makes sense.

Accessing secure restful web services using jersey client

I have created web services based on Jersey (auto generated via Netbeans).
I have also created a user names “testClient” with password “secret” and created User group “Users” and used file Realm using glassfish 3.0.1 admin console.
I have also mapped web.xml and sun-web.xml accordingly.
My web services are secured successfully; as I access the web site I receive a security warning and then I am prompt to give username and password to access any content of the website. It is working fine when accessed via web browser.
Now I have written a simple client based on jersey and tried to access the web services offered by the 1st project; the client code is here
Auto generated Jersey client code
public class JerseyClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(BASE_URI).path("manufacturers");
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
#Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
javax.net.ssl.TrustManager x509 = new javax.net.ssl.X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(null, new javax.net.ssl.TrustManager[]{x509}, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
}
Code in Main Method; uses auto generated code
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
// do whatever with response
client.close();
Results:
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128)
at com.sun.jersey.api.client.filter.HTTPBasicAuthFilter.handle(HTTPBasicAuthFilter.java:78)
at com.sun.jersey.api.client.Client.handle(Client.java:457)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557)
at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:69)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:451)
at clients.JerseyClient.get_XML(JerseyClient.java:23)
at clients.NewMain1.main(NewMain1.java:20)
Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1049)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:373)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:215)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:126)
... 7 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)
... 17 more
Java Result: 1
I also want to inform that these are two different projects running on different servers both are glassfish 3.0.1. I also tried to run client and services on the same server but all in vain. I am stuck; kindly help me.
Cheers!
i have found a good resource regarding my problem. Here it is
http://wiki.open-esb.java.net/attach/RestBCEchoSSL/SslClient.java
I made few changes in my code regarding the given source and it worked perfectly. Actually I was not passing the certificate and key stores properly.
Here is the full code.
package clients;
import com.sun.jersey.api.client.*;
import javax.net.ssl.*;
import java.io.*;
import java.net.Socket;
import java.security.*;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
public class JerseyClient {
private WebResource webResource;
private Client client;
//private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
private static final String truststore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/cacerts.jks";
private static final String truststore_password = "changeit";
private static final String keystore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/keystore.jks";
private static final String keystore_password = "changeit";
private static final String url = "https://localhost:9029/testsecurity2/resources/manufacturers/";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(url);
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
#Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
TrustManager mytm[] = null;
KeyManager mykm[] = null;
try {
mytm = new TrustManager[]{new MyX509TrustManager(truststore_path, truststore_password.toCharArray())};
mykm = new KeyManager[]{new MyX509KeyManager(keystore_path, keystore_password.toCharArray())};
} catch (Exception ex) {
ex.printStackTrace();
}
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(mykm, mytm, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
/**
* Taken from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509TrustManager implements X509TrustManager {
/*
* The default PKIX X509TrustManager9. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn't trust it.
*/
X509TrustManager pkixTrustManager;
MyX509TrustManager(String trustStore, char[] password) throws Exception {
this(new File(trustStore), password);
}
MyX509TrustManager(File trustStore, char[] password) throws Exception {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(trustStore), password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
/*
* Iterate over the returned trustmanagers, look
* for an instance of X509TrustManager. If found,
* use that as our "default" trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return pkixTrustManager.getAcceptedIssuers();
}
}
/**
* Inspired from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509KeyManager implements X509KeyManager {
/*
* The default PKIX X509KeyManager. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509KeyManager doesn't trust it.
*/
X509KeyManager pkixKeyManager;
MyX509KeyManager(String keyStore, char[] password) throws Exception {
this(new File(keyStore), password);
}
MyX509KeyManager(File keyStore, char[] password) throws Exception {
// create a "default" JSSE X509KeyManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStore), password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
kmf.init(ks, password);
KeyManager kms[] = kmf.getKeyManagers();
/*
* Iterate over the returned keymanagers, look
* for an instance of X509KeyManager. If found,
* use that as our "default" key manager.
*/
for (int i = 0; i < kms.length; i++) {
if (kms[i] instanceof X509KeyManager) {
pkixKeyManager = (X509KeyManager) kms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
public PrivateKey getPrivateKey(String arg0) {
return pkixKeyManager.getPrivateKey(arg0);
}
public X509Certificate[] getCertificateChain(String arg0) {
return pkixKeyManager.getCertificateChain(arg0);
}
public String[] getClientAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getClientAliases(arg0, arg1);
}
public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseClientAlias(arg0, arg1, arg2);
}
public String[] getServerAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getServerAliases(arg0, arg1);
}
public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseServerAlias(arg0, arg1, arg2);
}
}
}
and code to run the client in main class
public static void main(String[] args) {
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
System.out.println(response);
// do whatever with response
client.close();
}

Resources