WS Webservice template UnsupportedCallbackException - spring-boot

I am facing an issue with invoking webService template with ws security using keystores and interceptors, it returns
org.apache.wss4j.common.ext.WSSecurityException: Callback supplied no password for: 1
javax.security.auth.callback.UnsupportedCallbackException
where 1 is the key store alias..
bellow is the code I am using followed with the exception
public class SOAPConnector extends WebServiceGatewaySupport {
public Object callWebService() throws Exception {
KeyStore encryptionKeyStore = KeyStore.getInstance("JKS");
InputStream fis = new FileInputStream("C:\\Ahmed\\keyStore\\eip_stg_server_message_signature.jks");
encryptionKeyStore.load(fis, "changeit".toCharArray());
KeyStore signitureKeyStore = KeyStore.getInstance("JCEKS");
InputStream fis2 = new FileInputStream("C:\\Ahmed\\keyStore\\keystore2022_testing.jks");
signitureKeyStore.load(fis2, "changeit".toCharArray());
fis.close();
fis2.close();
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
Properties cryptoFactoryBeanConfig = new Properties();
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jceks");
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "changeit");
// from the class path
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.file", "C:\\Ahmed\\keyStore\\keystore2022_testing.jks");
cryptoFactoryBean.setConfiguration(cryptoFactoryBeanConfig);
cryptoFactoryBean.afterPropertiesSet();
CryptoFactoryBean cryptoFactoryBean2 = new CryptoFactoryBean();
Properties cryptoFactoryBeanConfig2 = new Properties();
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "changeit");
// from the class path
cryptoFactoryBeanConfig.setProperty("org.apache.ws.security.crypto.merlin.file", "C:\\Ahmed\\keyStore\\eip_stg_server_message_signature.jks");
cryptoFactoryBean2.setConfiguration(cryptoFactoryBeanConfig);
cryptoFactoryBean2.afterPropertiesSet();
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
interceptor.setSecurementActions("Signature Encrypt Timestamp");
interceptor.setSecurementPassword("changeit");
interceptor.setSecurementSignatureUser("1");
interceptor.setSecurementSignatureKeyIdentifier("DirectReference");
interceptor.setSecurementEncryptionKeyIdentifier("DirectReference");
interceptor.setSecurementSignatureCrypto(cryptoFactoryBean.getObject());
interceptor.setSecurementEncryptionCrypto(cryptoFactoryBean2.getObject());
interceptor.setSecurementEncryptionUser("eip stg server message signature (device ca - 2)");
//timeStamp
interceptor.setTimestampPrecisionInMilliseconds(false);
interceptor.setFutureTimeToLive(10000);
interceptor.setSecurementTimeToLive(10000);
interceptor.setValidationActions("Signature Encrypt Timestamp");
interceptor.setValidationTimeToLive(10000);
interceptor.setValidationSignatureCrypto(cryptoFactoryBean2.getObject());
interceptor.setValidationDecryptionCrypto(cryptoFactoryBean.getObject());
KeyStoreCallbackHandler ks = new KeyStoreCallbackHandler();
ks.setPrivateKeyPassword("changeit");
ks.setKeyStore(signitureKeyStore);
interceptor.setValidationCallbackHandler(ks);
WebServiceTemplate template = getWebServiceTemplate();
template.setInterceptors(new ClientInterceptor[]{interceptor});
String requestXml = "xml request";
StreamSource source = new StreamSource(new StringReader(requestXml));
StreamResult result = new StreamResult(System.out);
String uri = "url";
SoapActionCallback requestCallback = new SoapActionCallback("action_name");
try {
template.sendSourceAndReceiveToResult(uri, source, requestCallback, result);
}
catch (SoapFaultException sfe) {
throw new Exception("SoapFaultException", sfe);
}
catch (WebServiceTransportException wste) {
throw new Exception("WebServiceTransportException", wste);
}
return null;
}
it returns UnsupportedCallbackException
following is error details
Original Exception was org.apache.wss4j.common.ext.WSSecurityException: Callback supplied no password for: 1
Original Exception was javax.security.auth.callback.UnsupportedCallbackException
<?xml version="1.0" encoding="UTF-8"?><soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><faultcode>soapenv:Client</faultcode><faultstring xml:lang="en">Callback supplied no password for: 1; nested exception is org.apache.wss4j.common.ext.WSSecurityException: Callback supplied no password for: 1
Original Exception was org.apache.wss4j.common.ext.WSSecurityException: Callback supplied no password for: 1
Original Exception was javax.security.auth.callback.UnsupportedCallbackException</faultstring></soapenv:Fault>null
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Server Error
Process finished with exit code 0
I'm not sure what I am missing here
can any one relate please?
PS. I am using the same key stores with soap ui and it works fine

Related

Call RestApi endpoint resource from EJB

I have been looking around for sample code how to call a Restful service written in Spring boot (deployed in different server/ip) from an EJB client.
I couldn't find a simple example or reference to guide me on how to implement an EJB client that can call a restful service(deployed in different server/ip). Could you please point me to a document or example that shows or describe how the two can interface/talk to each other.
I need to call the endpoint by passing two header parameters for authentication, if authentication is success then only retrieve the details from Rest and send back the response to EJB client.
I use something like this, try
`public void calExternal() throws ProtocolException,
MalformedURLException,
IOException,
NoSuchAlgorithmException,
InvalidKeyException {
URL myurl = new URL("API END POINT URL");
ObjectMapper mapper = new ObjectMapper();
HttpURLConnection conn = (HttpURLConnection) myurl.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
String payLoad = mapper.writeValueAsString("your payload here");
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("AUTHORIZATION-TYPE", "HMAC");
try {
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(payLoad);
wr.flush();
InputStream in = null;
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
in = conn.getInputStream();
} else {
in = conn.getErrorStream();
}
String encoding = conn.getContentEncoding() == null ? "UTF-8" : conn.getContentEncoding();
String response = IOUtils.toString(in, encoding);
} catch (Exception e) {
e.printStackTrace();
}
}

unable to call a REST webservice..Full authentication required

I am currently working on spring application and REST webservices.
I have created a REST webservice in one application and want to access that service from other applications.
Below is the error its showing when trying to access the webservice.
RestClientException : org.springframework.web.client.HttpClientErrorException: 401 Full authentication is required to access this resource
Below is my webservice code:
#RequestMapping(value = MyRequestMapping.GET_ACC_DATA, method = RequestMethod.GET)
#ResponseBody
public MyResponseDTO getSigDataValues(#PathVariable final String acc, final HttpServletResponse response) throws Exception {
MyResponseDTO responseDTO = null;
try {
//logic goes here
//responseDTO = ..
} catch (Exception e) {
LOG.error("Exception" + e);
}
return responseDTO;
}
I am calling above webservice from another application.In the below mentioned method I am calling the webservice and its throwing me the exception org.springframework.web.client.HttpClientErrorException.
public MyResponseDTO getAccData(String acc){
try{
list= (List<String>)restTemplate.postForObject(MyDataURL.GET_ACC_DATA.value(), MyResponseDTO.class, acc);
}
catch (final RestClientException e)
{
LOG.info("RestClientException :" + e);
}
Please suggest, what am I missing.
You would need to authenticate against the REST service. One of the most common ways is Basic Authentication. If this is what the service is using you would need to create an AUTHORIZATION header with Base 64 encoded usernamen + password.
RestTemplate allow to set customer headers before the request gets sent.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
private HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {
private static final long serialVersionUID = -1704024310885506847L;
{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}
};
}
Then, sending a request becomes just as simple:
ResponseEntity<Dados> response = restTemplate.exchange(uriComponents.toUriString(), HttpMethod.GET,
new HttpEntity<Dados>(createHeaders(usuario, senha)), Dados.class);

while accessing profile data from google plus getting following exception my code is below

Exception in thread "main"
com.google.api.client.googleapis.json.GoogleJsonResponseException: 404
Not Found Not Found at
com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
at
com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at
com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at
com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at
com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1045)
at
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at googleplusdemo2.MyClass.main(MyClass.java:107)
public class MyClass {
// List the scopes your app requires:
private static List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.profiles.read",
"https://www.googleapis.com/auth/plus.circles.write",
"https://www.googleapis.com/auth/plus.stream.write",
"https://www.googleapis.com/auth/plus.stream.read");
// The following redirect URI causes Google to return a code to the user's
// browser that they then manually provide to your app to complete the
// OAuth flow.
private static final String REDIRECT_URI = "http://some url";
static String CLIENT_ID="myclient id";
static String CLIENT_SECRET="myclient secret";
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(),
new JacksonFactory(),
CLIENT_ID, // This comes from your Developers Console project
CLIENT_SECRET, // This, as well
SCOPE)
.setApprovalPrompt("force")
.setAccessType("offline").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
System.out.println("Please open the following URL in your browser then " +
"type the authorization code:");
System.out.println(" " + url);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String code = br.readLine();
// End of command line prompt for the authorization code.
GoogleTokenResponse tokenResponse = flow.newTokenRequest(code)
.setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.addRefreshListener(new CredentialRefreshListener() {
#Override
public void onTokenResponse(Credential credential, TokenResponse tokenResponse) {
// Handle success.
System.out.println("Credential was refreshed successfully.");
}
#Override
public void onTokenErrorResponse(Credential credential,
TokenErrorResponse tokenErrorResponse) {
// Handle error.
System.err.println("Credential was not refreshed successfully. "
+ "Redirect to error page or login screen.");
}
})
.build();
// Set authorized credentials.
credential.setFromTokenResponse(tokenResponse);
credential.refreshToken();
// Create a new authorized API client
PlusDomains plusDomains = new PlusDomains.Builder(new NetHttpTransport(), new JacksonFactory(), credential).setApplicationName("TESTMK3").build();
Person mePerson = plusDomains.people().get("me").execute();
mePerson.getGender();
System.out.println("ID:\t" + mePerson.getId());
System.out.println("Display Name:\t" + mePerson.getDisplayName());
System.out.println("Image URL:\t" + mePerson.getImage().getUrl());
System.out.println("Profile URL:\t" + mePerson.getUrl());
}
}

Jersey Response for Exception not working as Expected

I am authenticating user with name and password from my database.
If the user name or password is incorrect then I am throwing a custom Exception.
but I am not getting expected status code and response.
I am new to Jersey and web services.
This is my function which creates a response :
public static Response error(int Status_code, String Request_status ,String data, String Response_error){
ResponseBuilder response = new ResponseBuilder();
response.Status_code = Status_code;
response.Request_status = Request_status;
response.data =data;
response.Response_error = Response_error;
return Response.status(Status_code).entity(response).build();
}
This is my custom Exception class code :
public class InvalidcredentialsException extends WebApplicationException {
public InvalidcredentialsException(Response response ) {
super(response);
}
}
This is how I am throwing this exception in my code if credentials are wrong(user name and password) in AuthenticateUser function in my Model.
throw new InvalidcredentialsException(ResponseBuilder.error(Response.Status.UNAUTHORIZED.getStatusCode(),"success","","invalid credentials"));
When I am checking my API I am getting 204 as response , but I am expecting a JSON with the parameters which I have provided.
I have implemented my API in the following way :
#Path("/user")
public class User {
#POST
#Path("/login")
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/json")
public void UserAuthentication(UserCredentials user) {
UserModel userAuthentication = new UserModel();
userAuthentication.AuthenticateUser(user);
}
}
I have used the following link to create Exception and throw :
JAX-RS / Jersey how to customize error handling?
This is my authenticate function :
public void AuthenticateUser(UserCredentials user) {
Database db = new Database();
Connection con = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
try {
String username = user.getUsername();
String password = user.getPassword();
con = db.getConnection();
if (con != null) {
String selectQuery_UserDetails = "SELECT name,password FROM user WHERE name=? AND password = ?";
preparedStatement = con.prepareStatement(selectQuery_UserDetails);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
rs = preparedStatement.executeQuery();
if (!rs.isBeforeFirst()) {
throw new InvalidcredentialsException(ResponseBuilder.error(Response.Status.UNAUTHORIZED.getStatusCode(),"success","","invalid credentials"));
}
}}catch (SQLException e) {
} finally {
db.closeConnection(con);
}
}
Thanks
You are catching but not handling the SQLException. When an error occurs, while accessing or trying to access the database, the exception is ignored and no error response is created. Maybe the database is not accessible or configured incorrectly.
You should wrap the exception into a RuntimeException like javax.ws.rs.InternalServerErrorException or just remove the catch statement. And you should log the error here or in an exception mapper, so that you are able to analyze and fix the problem.
I suggest to wrap the exception and log it like that:
}catch(SQLException e){
logger.log(Level.SEVERE, "db error while authenticate user", e);
throw new InternalServerErrorException("db error while authenticate user", e);
}
Now the runtime exception will be handled by a default exception mapper, which will generate the error response. Additional the error is logged. In this code I used java.util.logging - if necessary adjust it to the logging api you use.

sheets api error access denied exception desp Requested client not authorized

Hi I am using Google apis.. I have successfully able to access google drive and google calendar but when i try to access google spreadsheet i am getting following exception.
Exception in thread "main" com.google.gdata.util.AuthenticationException: Failed to refresh access token: 403 Forbidden
{
"error" : "access_denied",
"error_description" : "Requested client not authorized."
}
Caused by: com.google.api.client.auth.oauth2.TokenResponseException: 403 Forbidden
{
"error" : "access_denied",
"error_description" : "Requested client not authorized."
}
My code is as follows
private static Credential authorize() throws Exception {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
String SERVICE_ACCOUNT_EMAIL = "xxx#developer.gserviceaccount.com";
List<String> SCOPES = Arrays.asList("https://spreadsheets.google.com/feeds/");
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory).setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File("xxx.p12"))
.setServiceAccountUser("xx#zzz.com")
.build();
return credential;
}
public static void main(String[] args) throws Exception {
Credential credential = authorize();
SpreadsheetService service = new SpreadsheetService("new data service ");
service.setProtocolVersion(SpreadsheetService.Versions.V3);
service.setOAuth2Credentials(credential);
// Define the URL to request. This should never change.
URL SPREADSHEET_FEED_URL = new URL(
"https://spreadsheets.google.com/feeds/spreadsheets/private/full");
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
// Iterate through all of the spreadsheets returned
for (SpreadsheetEntry spreadsheet : spreadsheets) {
// Print the title of this spreadsheet to the screen
System.out.println(spreadsheet.getTitle().getPlainText());
}
}
Thanks
I was only passing the spreadsheet scope, I have to pass both drive and sheet scope. Now I am able to read spreadsheets from drive.. Here is the corrected code.
String SERVICE_ACCOUNT_EMAIL = "xxxx#developer.gserviceaccount.com";
ArrayList<String> scopes = new ArrayList<String>();
scopes.add(0, DriveScopes.DRIVE);
scopes.add(1, "https://spreadsheets.google.com/feeds");
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory).setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(scopes)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File("xx.p12"))
.setServiceAccountUser("yyy#example.com")
.build();

Resources