My project requires integration with G-Suite and AzureAD directory. Both of them supports OAuth2 as explained here and here.
I want to access G-Suite and AzueAD API with Google OAuth2 client. I have few questions for the same
Is it possible to access AzureAD API using google-oauth-api-client?
Is there any library which can be used with G-Suite SDK and AzureAD?
I don't want to separate library for each provider I integrate. Be it G-Suite or AzureAD or SalesForce or something else which supports OAuth2.
The Google OAuth2 client library can be used to authenticate against any OAuth2 provider by adding the following two classes:
public class ClientUsernamePasswordTokenRequest extends TokenRequest {
/**
* #param transport HTTP transport
* #param jsonFactory JSON factory
* #param tokenServerUrl token server URL
* #param grantType grant type ({#code "authorization_code"}, {#code "password"},
* {#code "client_credentials"}, {#code "refresh_token"} or absolute URI of the extension
*/
public ClientUsernamePasswordTokenRequest(HttpTransport transport, JsonFactory jsonFactory, GenericUrl tokenServerUrl, String grantType) {
super(transport, jsonFactory, tokenServerUrl, grantType);
}
#Override
public TokenResponse execute() throws IOException {
return convertStringToObject(executeUnparsed().parseAs(Map.class));
}
private TokenResponse convertStringToObject(Map content) {
TokenResponse tokenResponse = new TokenResponse();
String tokenType = (String) content.get("token_type");
tokenResponse.setTokenType(tokenType);
String scope = (String) content.get("scope");
tokenResponse.setScope(scope);
String accessToken = (String) content.get("access_token");
tokenResponse.setAccessToken(accessToken);
String refreshToken = (String) content.get("refresh_token");
tokenResponse.setRefreshToken(refreshToken);
return tokenResponse;
}
}
and
package com.identityforge.idfserver.backend.rest.auth;
import com.google.api.client.http.HttpExecuteInterceptor;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.UrlEncodedContent;
import com.google.api.client.util.Data;
import com.google.api.client.util.Preconditions;
import java.util.Map;
public class ClientParametersAuthentication implements HttpRequestInitializer, HttpExecuteInterceptor {
/**
* Client identifier issued to the client during the registration process.
*/
private final String clientId;
/**
* Client password or {#code null} for none.
*/
private final String password;
/**
* Client username
*/
private final String username;
/**
* Resource for which access is requested
*/
private final String resource;
private final String clientSecret;
/**
* #param clientId client identifier issued to the client during the registration process
* #param password password or {#code null} for none
* #param username
* #param resource
* #param clientSecret
*/
public ClientParametersAuthentication(String clientId, String password, String username, String resource, String clientSecret) {
this.clientId = Preconditions.checkNotNull(clientId);
this.password = Preconditions.checkNotNull(password);
this.username = Preconditions.checkNotNull(username);
this.resource = resource;
this.clientSecret = clientSecret;
}
public void initialize(HttpRequest request) {
request.setInterceptor(this);
}
public void intercept(HttpRequest request) {
Map<String, Object> data = Data.mapOf(UrlEncodedContent.getContent(request).getData());
data.put("client_id", clientId);
data.put("password", password);
data.put("username", username);
if (resource != null)
data.put("resource", resource);
if (clientSecret != null) {
data.put("client_secret", clientSecret);
}
}
}
Now access token can be requested by providing credentials values in the following code
private void fetchToken() throws IOException {
TokenResponse tokenResponse;
if (genericUrl == null) {
genericUrl = new GenericUrl(tokenUrl);
}
if (authentication == null) {
authentication = new ClientParametersAuthentication(clientId, passwd, username, resource, clientSecret);
}
if (tokenRequest == null) {
tokenRequest = new ClientUsernamePasswordTokenRequest(new ApacheHttpTransport(), JacksonFactory.getDefaultInstance(), genericUrl, grantType);
tokenRequest.setClientAuthentication(authentication);
}
tokenResponse = tokenRequest.execute();
String accessToken = tokenResponse.getAccessToken();
}
Here tokenUrl is the authentication endpoint.
Related
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() {
}
}
I try to implement my own custom CredentialsAuthProvider. The server seems to work fine with the following implementation:
public class MyCustomCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
if (userName == "testuser" && password == "1234")
{
return true;
}
else
{
return false;
}
}
public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens,
Dictionary<string, string> authInfo)
{
session.FirstName = "Testuser Joe Doe";
authService.SaveSession(session, SessionExpiry);
return null;
}
}
When I call on my Browser http://localhost:8088/auth/credentials?UserName=testuser&Password=1234 I get back a page containing a session ID and the testuser Joe Doe. Looks fine.
Now I try to call this from my Windows WPF client. I have created a Login Page and a LoginViewModel class since I implement the MVVM pattern. But I do not understand, what I really have to set the provider property in the Authenticate class to.
In my WPF class I have the following:
public partial class App : Application
{
public JsonServiceClient ServiceClient { get; private set; }
public App()
{
this.InitializeComponent();
}
// ....
}
And then in my LoginViewModel I have a Login() method which is a RelayCommand implementation of the login button like so (The form contains also a field where you have to enter the name of the application server since there is more than one. This is why I compose the baseUri in the handler):
private void Login()
{
var baseUri = $"http://{AppServer}:8088";
((App)Application.Current).InitServiceClient(baseUri);
var client = ((App) Application.Current).ServiceClient;
//var response = client.Send<AuthResponse>(new Auth { UserName = "Test", Password = "TestPassword" });
var authResponse = client.Post(new Authenticate
{
provider = CredentialsAuthProvider.Name, // <-- WHAT SHOULD THIS BE???
UserName = "testuser",
Password = "1234",
RememberMe = true,
});
// ....
}
CredentialsAuthProvider is unknown by the compiler. What do I need to pass here and what assemblies do I need? So far I have:
ServiceStack.Ckient
ServiceStack.Interfaces
ServiceStack.Text
MyService.ServiceModel //DLL containing the DTOs etc., NO implementations
What am I missing and doing wrong here?
CredentialsAuthProvider.Name just provides typed access to the "credentials" string literal, which you can use in its place, e.g:
var authResponse = client.Post(new Authenticate
{
provider = "credentials",
UserName = "testuser",
Password = "1234",
RememberMe = true,
});
You can find the list of Auth provider literals in the Authentication docs.
I am new to web services and currently trying to setup Restlet on Apache Karaf. My Core bundle starts component with Protocol: HTTP. And Port: 8081.
I have created a component in which uses HTTP Protocol and a port number configured via property.
Applications are attached to default host as
wsComponent.getDefaultHost().attach(restletApp.getURI(),restletApp);
In above getURI function returns URL to which application is attached.
I am trying to use JaxbRepresentation to get details. Server Resource class is as follows:
#Get
public Representation getAllUsers()
{
List<MyUser> allUsers = MyFactory.getInstance().getAllUsers();
MyUserListXML userListXML = new MyUserListXML(MyUserConverter.convertMyUserList(allUsers));
JaxbRepresentation<MyUserListXML> userReps = new JaxbRepresentation<MyUserListXML>(userListXML);
userReps.setFormattedOutput(true);
return userReps;
}
MyUserListXML.java:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder={"user"})
#XmlRootElement(name="myUsers")
public class MyUserListXML implements Serializable
{
private static final long serialVersionUID = 1L;
#XmlElement(name="user")
private List<MyUserXML> userList;
public MyUserListXML()
{
// Default Constructor
}
/**
* #param userList
*/
public MyUserListXML(List<MyUserXML> userList)
{
this.userList = userList;
}
/**
* #return the userList
*/
public List<MyUserXML> getUserList()
{
return userList;
}
/**
* #param userList the userList to set
*/
public void setUserList(List<MyUserXML> userList)
{
this.userList = userList;
}
}
MyUserXML.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"id","userName","status","displayName","email"})
#XmlRootElement(name = "esmfUser")
public class MyUserXML implements Serializable
{
private static final long serialVersionUID = 1L;
#XmlElement(name= "id", required=true,type=Integer.class)
private Integer userId;
#XmlElement(required=true)
private String userName;
#XmlElement(name="status",required=true)
private String userStatus;
#XmlElement(required=true)
private String displayName;
#XmlElement(required=true)
private String email;
public MyUserXML()
{
// default constructor.
}
/**
* #param userId
* #param userName
* #param userStatus
* #param displayName
* #param email
*/
public MyUserXML(Integer userId, String userName, String userStatus, String displayName, String email)
{
this.userId = userId;
this.userName = userName;
this.userStatus = userStatus;
this.displayName = displayName;
this.email = email;
}
/**
* #return the userId
*/
public Integer getUserId()
{
return userId;
}
/**
* #param userId the userId to set
*/
public void setUserId(Integer userId)
{
this.userId = userId;
}
/**
* #return the userName
*/
public String getUserName()
{
return userName;
}
/**
* #param userName the userName to set
*/
public void setUserName(String userName)
{
this.userName = userName;
}
/**
* #return the userStatus
*/
public String getUserStatus()
{
return userStatus;
}
/**
* #param userStatus the userStatus to set
*/
public void setUserStatus(String userStatus)
{
this.userStatus = userStatus;
}
/**
* #return the displayName
*/
public String getDisplayName()
{
return displayName;
}
/**
* #param displayName the displayName to set
*/
public void setDisplayName(String displayName)
{
this.displayName = displayName;
}
/**
* #return the email
*/
public String getEmail()
{
return email;
}
/**
* #param email the email to set
*/
public void setEmail(String email)
{
this.email = email;
}
}
While testing using soapUI I am getting following request and response
Request:
GET http://localhost:8081/ws/users HTTP/1.1
Accept-Encoding: gzip,deflate
Host: localhost:8081
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Response:
HTTP/1.1 200 OK
Content-encoding: gzip, zip, deflate
Server: Restlet-Framework/2.3.5
Date: Sun, 15 Nov 2015 09:29:31 GMT
Transfer-encoding: chunked
Content-type: application/xml; charset=UTF-8
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Accept-ranges: bytes
I am not sure why I am not getting xml data out. Can any one help me or guide me what I am doing wrong.
Restlet version: 2.3.5
I was able to resolve this issue.
I have created ObjectFactory class but changed its name. Due to this JaxbContext was not able to find ObjectFactory class. And since I am using restlet in Osgi and not yet able to figure out how to make Restlet use Osgi Log Service was not seeing any error messages from restlet.
Regarding the issue with JaxB, you should at least see a Warning log trace, and probably a IOException. I have a look at the issue you created (https://github.com/restlet/restlet-framework-java/issues/1166).
If you want to list all log traces from Restlet framework, and actually from any other kind of library that you include in your project and that don't rely on the OSGi LogService, you must configure the logs according to each library requirements (JUL, Log4j, slf4j, etc). As an OSGi container is basically a JVM, there is no issue to configure each logger.
Regarding Restlet Framework, you can read this page: http://restlet.com/technical-resources/restlet-framework/guide/2.3/editions/jse/logging
Some technologies such as slf4j helps to mutualize the different log systems. You should be able to pour all logs into the OSGi LogService, if you want to.
I am using couchdb4j api to establish a connection through session object with couchdb(version 0.11.2).
Couchdb database is protected with username and password,
trying to establish connection with
Session(String host, int port, String user, String pass, boolean usesAuth, boolean secure) constructor by providing host,port,user,pass and usersAuth true, secure false,
but it is unable to establish a connection with username and password and giving a warning Authentication error: Unable to respond to any of these challenges: {}.
I used correct username and password.
Try a CouchDB lib that is actively maintained http://www.ektorp.org/ instead.
I solved the same issue by writing a simple Curl class that simplified the communication and return JSON in String form, since that is what is returned.
It should be self explanatory and you can read the main method for hints.
package path.to.the.class;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import Log;
/**
* This class takes on the simple task of doing http calls to any http web service like a web page or alike. Since the
* class is streamlined for JSON use this is the most easiest to set up.
*
* #author mikael.p.larsson#epsilon.nu
*
*/
public class Curl {
private Map<String, String> requestProperties = null;
private String charsetName = "UTF8";
public static final String GET = "GET";
public static final String PUT = "PUT";
public static final String POST = "POST";
public static final String HEAD = "HEAD";
public static final String DELETE = "DELETE";
/**
* This is the default constructor for Curl which takes it for granted that you want to communicate and read JSON.
* Most of the times this approach works even if plain html or text is requested.
*/
public Curl() {
requestProperties = new HashMap<String, String>();
requestProperties.put("Content-Type", "application/json");
}
/**
* With this alternate constructor a map containing header strings can be provided, useful if something apart from
* JSON is to be consumed.
*
* #param requestProperties
* a Map containing the header strings.
*/
public Curl(Map<String, String> requestProperties) {
this.requestProperties = requestProperties;
}
/**
* Public setter to enable setting charsetName.
*
* #param charsetName
* #return this instance to enable on liners.
*/
public Curl setCharsetName(String charsetName) {
this.charsetName = charsetName;
return this;
}
/**
* In the world of the web this is the command that a web browser does for you after you have entered an url into
* the address field. When using GET there should be no side effects on the site the data was requested from; the
* get method only consumes data and sends nothing.
*
* #param urlAsString
* the url to fetch from the internet.
* #return The response from the server
*/
public String get(String urlAsString) {
return doHttpCall(urlAsString, GET, null);
}
/**
* Put should be used when a resource should be sent to a server.
*
* #param urlAsString
* the url to the resource.
* #param doc
* the content to put
* #return The response from the server.
*/
public String put(String urlAsString, String doc) {
return doHttpCall(urlAsString, "PUT", doc);
}
/**
* Post should be used when a resource should be posted to a server.
*
* #param urlAsString
* the url to the resource.
* #param doc
* the content to put
* #return The response from the server.
*/
public String post(String urlAsString, String doc) {
return doHttpCall(urlAsString, "POST", doc);
}
/**
* Mostly to be considered as a get without the contents, Here implemented as an is the resource available function.
*
* #param urlAsString
* the url to the resource.
* #return The responseMessage from the server.
*/
public String head(String urlAsString) {
return doHttpCall(urlAsString, "HEAD", null);
}
/**
* Deletes a resource from an url. Be careful!
*
* #param urlAsString
* The url to the resource to delete.
* #return The response from the server.
*/
public String delete(String urlAsString) {
try {
return doHttpCall(urlAsString, "DELETE", null);
} catch (Exception e) {
Log.warn("No object to delete found at " + urlAsString + ".");
return "No object to delete found at " + urlAsString + ".";
}
}
/**
* This method does the actual HTTP communication to simplify the methods above.
*
* #param urlAsString
* The url to resource in question.
* #param method
* The method to be used.
* #param doc
* The resource to send or null if none.
* #return The response from the server.
*/
private String doHttpCall(String urlAsString, String method, String doc) {
StringBuffer result = new StringBuffer();
HttpURLConnection httpUrlConnection = null;
try {
URL url = new URL(urlAsString);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setDoInput(true);
httpUrlConnection.setRequestMethod(method);
if (url.getUserInfo() != null) {
String basicAuth = "Basic " + new String(new Base64().encode(url.getUserInfo().getBytes()));
httpUrlConnection.setRequestProperty("Authorization", basicAuth);
}
httpUrlConnection.setRequestProperty("Content-Length", "0");
for (String key : requestProperties.keySet()) {
httpUrlConnection.setRequestProperty(key, requestProperties.get(key));
}
if (doc != null && !doc.isEmpty()) {
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setRequestProperty("Content-Length", "" + doc.getBytes(charsetName));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpUrlConnection.getOutputStream(),
charsetName);
outputStreamWriter.write(doc);
outputStreamWriter.close();
}
readInputStream(result, httpUrlConnection.getInputStream());
} catch (RuntimeException e) {
Log.info(e.getMessage());
} catch (MalformedURLException e) {
Log.warn("The url '" + urlAsString + "' is malformed.");
} catch (IOException e) {
try {
result.append(e.getMessage());
readInputStream(result, httpUrlConnection.getErrorStream());
if ("".equals(result.toString())) {
result.append("Error ");
result.append(httpUrlConnection.getResponseCode());
result.append(" : ");
result.append(httpUrlConnection.getResponseMessage());
result.append(". Exception message is: [");
result.append(e.getMessage());
result.append("]");
}
} catch (IOException e1) {
}
} finally {
if ("HEAD".equalsIgnoreCase(method)) {
try {
result.append(httpUrlConnection.getResponseMessage());
} catch (IOException e) {
Log.fatal("This is as low as we can get, nothing worked!");
e.printStackTrace();
}
}
if (httpUrlConnection != null)
httpUrlConnection.disconnect();
}
return result.toString();
}
/**
* Local helper method that reads data from an inputstream.
*
* #param result
* The read text.
* #param inputStream
* The stream to read.
* #throws UnsupportedEncodingException
* #throws IOException
*/
private void readInputStream(StringBuffer result, InputStream inputStream) throws UnsupportedEncodingException,
IOException {
if (inputStream == null)
throw new IOException("No working inputStream.");
InputStreamReader streamReader = new InputStreamReader(inputStream, charsetName);
BufferedReader bufferedReader = new BufferedReader(streamReader);
String row;
while ((row = bufferedReader.readLine()) != null) {
result.append(row);
result.append("\n");
}
bufferedReader.close();
streamReader.close();
}
/**
* A main method to provide the possibility to use this exact class from the command line.
* <p>
* usage:
* <code>java -cp target/classes/. path.to.the.class.Curl http://server.domain.nu:port/path/to/resource method [data]</code>
* </p>
*
* #param args
* in order: url method data
*/
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("usage: Curl path method [data]");
System.exit(0);
}
String url = args[0];
String method = args[1];
String data = args.length == 3 ? args[2] : null;
Curl curl = new Curl();
if (method.equals("head")) {
System.out.println(curl.head(url));
System.exit(0);
}
if (method.equals("put")) {
System.out.println(curl.put(url, data));
System.exit(0);
}
System.out.println(curl.doHttpCall(url, method, data));
}
}
Try change configuration parameter required_valid_user to true
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();
}