How can i get https responses on google app engine? - google-app-engine

I get this exception when trying to fetch response for an https link
javax.net.ssl.SSLHandshakeException: Could not verify SSL certificate for: https://[...link...]
Below is the code I use. What am I doing wrong?
URL productsURL = new URL(link + authenticationExtension);
URLConnection connection = productsURL.openConnection();
connection.setRequestProperty("Authorization", "Basic " + userNamePasswordB64);
connection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));

See the FetchOptions doNotValidateCertificate method. There is a note about this in the URL Fetch docs.

Related

My code fails for https with bad request and works for http

I have tried everything available on line but in vain. The code below works for http and not https.
I have tls 1.2 enable on my system and ssl certificate is self signed that I am using with https and using IIS web server from MS.
Also when I try to access the url from IIS Browse Website I see the same error with these details:
This error (HTTP 400 Bad Request) means that Internet Explorer was able to connect to the web server, but the webpage could not be found because of a problem with the address.
But there are no issues with the address.
I also see this error in the event viewer:
The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID
{2593F8B9-4EAF-457C-B68A-50F6B8EA6B54}
and APPID
{15C20B67-12E7-4BB6-92BB-7AFF07997402}
to the user CORP\qahee SID (S-1-5-21-606747145-1993962763-839522115-104115) from address LocalHost (Using LRPC) running in the application container Unavailable SID (Unavailable). This security permission can be modified using the Component Services administrative tool.
Though I have changed the permission to full control in the registry for the user CORP\qahee and have rebooted the system before trying again I still get the error.
I have all three version of tls enabled in the registry and also in the internet options.
I wonder if the issue is due to self signed certificate.
Here is my code:
private string GetSessionId(string id)
{
var url
System.Configuration.ConfigurationManager.AppSettings["SessionServerURL"] ??"http://localhost";
System.Net.ServicePointManager.SecurityProtocol |=
System.Net.SecurityProtocolType.Tls12 |
System.Net.SecurityProtocolType.Tls11 |
System.Net.SecurityProtocolType.Tls;
using (var handler = new HttpClientHandler() { UseDefaultCredentials =
true })
{
handler.ServerCertificateCustomValidationCallback =
ServerCertificateCustomValidation;
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
newMediaTypeWithQualityHeaderValue("application/json"));
logger.Debug("handler: " + handler + " url: " + url +
" BaseAddress: " + client.BaseAddress);
// HTTP GET
try
{
HttpResponseMessage response =
client.GetAsync("/System/StartSession/" + id).Result;
logger.Debug("response status: " +
response.StatusCode +
" req msg: " + response.RequestMessage +
" reasonphrase:+response.ReasonPhrase);
if (response.IsSuccessStatusCode)
{
var jsonText =
response.Content.ReadAsStringAsync().Result;
var result =
JsonConvert.DeserializeObject<string>(jsonText);
return result;
}
}
This is the output for http when it runs w/o failure:
response status: OK req msg: Method: GET, RequestUri: 'http://localhost:83/System/StartSession/434f52505c7161686565', Version: 1.1, Content: , Headers:
{
Accept: application/json
} reason phrase: OK
For https this is the failure I get
response status: BadRequest req msg: Method: GET, RequestUri: 'https://abe-s19-qe1.qae.xxx.com:444/System/StartSession/434f52505c7161686565', Version: 1.1, Content: , Headers:
{
Accept: application/json
} reason phrase: Bad Request

Service account request to IAP-protected app results in 'Invalid GCIP ID token: JWT signature is invalid'

I am trying to programmatically access an IAP-protected App Engine Standard app via Python from outside of the GCP environment.
I have tried various methods, including the method shown in the docs here: https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python. Here is my code:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
print(f'{open_id_connect_token=}')
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
print(f'{resp=}')
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
if __name__ == '__main__':
res = make_iap_request(
'https://MYAPP.ue.r.appspot.com/',
'Client ID from IAP>App Engine app>Edit OAuth Client>Client ID'
)
print(res)
When I run it locally, I have the GOOGLE_APPLICATION_CREDENTIALS environment variable set to a local JSON credential file containing the keys for the service account I want to use. I have also tried running this in Cloud Functions so it would presumably use the metadata service to pick up the App Engine default service account (I think?).
In both cases, I am able to generate a token that appears valid. Using jwt.io, I see that it contains the expected data and the signature is valid. However, when I make a request to the app using the token, I always get this exception:
Bad response from application: 401 / {'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Tue, 09 Feb 2021 19:25:43 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '47', 'Alt-Svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"'} / 'Invalid GCIP ID token: JWT signature is invalid'
What could I be doing wrong?
The solution to this problem is to exchange the Google Identity Token for an Identity Platform Identity Token.
The reason for the error Invalid GCIP ID token: JWT signature is invalid is caused by using a Google Identity Token which is signed by a Google RSA private key and not by a Google Identity Platform RSA private key. I overlooked GCIP in the error message, which would have told me the solution once we validated that the token was not corrupted in use.
In the question, this line of code fetches the Google Identity Token:
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
The above line of code requires that Google Cloud Application Default Credentials are setup. Example: set GOOGLE_APPLICATION_CREDENTIALS=c:\config\service-account.json
The next step is to exchange this token for an Identity Platform token:
def exchange_google_id_token_for_gcip_id_token(google_open_id_connect_token):
SIGN_IN_WITH_IDP_API = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp'
API_KEY = '';
url = SIGN_IN_WITH_IDP_API + '?key=' + API_KEY;
data={
'requestUri': 'http://localhost',
'returnSecureToken': True,
'postBody':'id_token=' + google_open_id_connect_token + '&providerId=google.com'}
try:
resp = requests.post(url, data)
res = resp.json()
if 'error' in res:
print("Error: {}".format(res['error']['message']))
exit(1)
# print(res)
return res['idToken']
except Exception as ex:
print("Exception: {}".format(ex))
exit(1)
The API Key can be found in the Google Cloud Console -> Identity Platform. Top right "Application Setup Details". This will show the apiKey and authDomain.
More information can be found at this link:
Exchanging a Google token for an Identity Platform token

Resumable upload in Google Drive Rest API V3 from Salesforce apex / REST Client

I am trying to create a resumable upload session using drive rest API in Salesforce Apex.
As per the documentation the 3 steps needed to be followed are
Start a resumable session
Save the resumable session URI
Upload the file
But i am not able to retrieve the Location header from the response. Even i tried the request from the postman rest client, it is having the same problem.
Code :
String body='{ "name" : "'+ filename+'",'+'"parents": ["0B3fYScqCn4pyWGRZVUIwWnNIbDg"] }';
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://www.googleapis.com/drive/v3/files?uploadType=resumable');
req.setHeader('Authorization', 'Bearer ' +accessToken);
system.debug('###accessToken'+accessToken);
req.setHeader('Content-Type', 'application/json;charset=UTF-8');
req.setHeader('Content-length', String.valueOf(body.length()));
req.setHeader('X-Upload-Content-Type',fileType);
req.setHeader('X-Upload-Content-Length',String.valueOf(fileSize));
req.setBody(body);
req.setMethod('POST');
//req.setTimeout(60*1000);
HttpResponse resp = http.send(req);
system.debug('###fileSize'+fileSize);
system.debug('#######---'+resp.getbody());
system.debug('#######---'+resp.getHeader('Location')); //returning null
for(String str : resp.getHeaderKeys()){
system.debug('#######---str:'+str+':: '+resp.getHeader(str));
//no header with location /Location
}
Response :
{
"kind": "drive#file",
"id": "0B3fYScqCn4pyaGRYN214MnpiV2s",
"name": "Untitled",
"mimeType": "application/octet-stream"
}
Are you using v2 or v3 of the API? Your endpoint is v2, your question states v3.
Did you try your code with the correct endpoint?
https://www.googleapis.com/upload/drive/v3/files

Cant download file from webservice using MTOM and Axis2 stub

I m trying to download a file from my Axis2 webservice server using MTOM and ADB.
I can download the file if I dont enable the MTOM both on server and the client sides. Any suggestions or code sample would be nice :)
Client side
ServerWSStub stub = new ServerWSStub();
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_MTOM,Constants.VALUE_TRUE);
Server side axis2.xml
<parameter name="enableMTOM">optional</parameter>
This is my Server
public DataHandler download(String konum) throws Exception {
System.out.println("The filePath for download: " + konum);
FileDataSource dataSource = new FileDataSource(konum);
DataHandler datahandler = new DataHandler(dataSource);
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace ns = fac.createOMNamespace("http://benim.projem.org/dosya", "dosyam");
OMText textData = fac.createOMText(datahandler, true);
OMElement ele = fac.createOMElement("sonuc", ns);
ele.addChild(textData);
System.out.println(ele);
return datahandler;
This is my Client
ServerWSStub stub = new ServerWSStub();
//stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_MTOM,Constants.VALUE_TRUE);
//when uncommented i get java.lang.NoClassDefFoundError: org/apache/james/mime4j/MimeException
//while trying to invoke _operationClient.execute(true); in ServerWSStub
//I guess it is because of wrong unparsing
Download download = new Download();
download.setKonum(konum);
try {
DownloadResponse downloadResponse = stub.download(download);
DataHandler dh =(DataHandler) downloadResponse.get_return();
File file = new File("C:/dosya/"+fileNameType);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(file);
dh.writeTo(fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (ServerWSExceptionException e) {
e.printStackTrace();
}
Any
I finally got the solution I guess. The Stream closes before the client gets the whole file thats why first I used the getOptions().setTimeOutInMilliSeconds(10000) method but it was also useless and then in the Stub file I commented
_messageContext.getTransportOut().getSender().cleanup(_messageContext);//look for the method's finally part
part so that during a large file transportation the stream had not been closed and i could download the whole file without any silly exceptions :)
--MIMEBoundary_e56e8a77b94fbdd7678582aa5ca53f50b1d56c0d828499ea
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <0.146e8a77b94fbdd7678582aa5ca53f50b1d56c0d828499ea#apache.org>
<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns:downloadResponse xmlns:ns="http://servis.ws.projem.tez.benim"><ns:return><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:1.046e8a77b94fbdd7678582aa5ca53f50b1d56c0d828499ea#apache.org" /></ns:return></ns:downloadResponse></soapenv:Body></soapenv:Envelope>
--MIMEBoundary_e56e8a77b94fbdd7678582aa5ca53f50b1d56c0d828499ea
Content-Type: text/plain
Content-Transfer-Encoding: binary
Content-ID: <1.046e8a77b94fbdd7678582aa5ca53f50b1d56c0d828499ea#apache.org>
binary code here
Simply add apache-mime4j-core-0.7.2.jar to WEB-INF/lib on the service (server) side. The jar can be found here.

CXF - catching/handling HTTP exceptions

This is rather a basic cxf usage question. How/where can we catch the actual HTTP exception/error. I kind of followed the Interceptor/MessageObserver concept but could not capture the HTTP error using them.
I see this error in the log4j log file.
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response
'401: Unauthorized' when communicating with http://10.107.172.79/test/_vti_bin/lists.asmx
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1502)
at org.apache.cxf.transpot.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1448)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1356)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:614)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
... 9 more
Only javax.xml.ws.WebServiceException with "Could not send Message."
message is thrown while calling the service
try{
GetListCollectionResult result = port.getListCollection();
}catch (javax.xml.ws.WebServiceException excep){
}
This is how we call the service.
To provide NTLM credentials:
Authenticator.setDefault( extended class of Authenticator);
Create the service.
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ListsSoap.class);
factory.setAddress(list_url);
ListsSoap port = (ListsSoap) factory.create();
Update the conduit.
..
Client client = ClientProxy.getClient(port);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
http.setClient(httpClientPolicy);
Call service and get the result.
GetListCollectionResult result = port.getListCollection();
Nevermind, I found the answer in the CXF mailing list.
excep.getCause()
gives access to the underlying exception, in my case it is the HTTP Transport exception.

Resources