I'm trying to implement this example,
https://google-developers.appspot.com/drive/auth/web-server
however the following classes are not found! Oauth2, Userinfo
static User getUserInfo(Credential credentials)
throws NoUserIdException {
Oauth2 userInfoService =
new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credentials).build();
Userinfo userInfo = null;
try {
userInfo = userInfoService.userinfo().get().execute();
} catch (IOException e) {
System.err.println("An error occurred: " + e);
}
if (userInfo != null && userInfo.getId() != null) {
return userInfo;
} else {
throw new NoUserIdException();
}
}
All other classes were found. I have the latest Drive libraries in my build path (Eclipse).
This example is all kinds of messed up. I've implemented OAuth before and this is just way too verbose and over-complicated. It's not even obvious where the user is sent to Google to authenticate.
Had to add
https://developers.google.com/api-client-library/java/apis/oauth2/v2
Drive SDK has com.google.api.client.auth.oauth2, but not com.google.api.services.oauth2! Go figure!
And it STILL doesn't work.
Type mismatch: cannot convert from Userinfo to User
So I had to change the return type to Userinfo.
Related
I am implementing "Login with Microsoft button" and I need to store the refresh token in my database so that I can use that to obtain new access tokens in future. I am trying to do this with Java sdk for microsoft graph.
Edit 1: I actually want to create calendar events using my web application. So, the goal is for the web app to access Graph API without having a signed in user present.
This is what the code looks like:
AuthorizationCode authorizationCode = new AuthorizationCode(httpServletRequest.getParameter("code"));
String currentUri = httpServletRequest.getRequestURL().toString();
IAuthenticationResult result;
ConfidentialClientApplication app;
try {
app = createClientApplication();
String authCode = authorizationCode.getValue();
Set<String> scopes = new HashSet<String>();
scopes.add("Calendars.ReadWrite");
AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(authCode, new URI(currentUri)).scopes(scopes)
.build();
Future<IAuthenticationResult> future = app.acquireToken(parameters);
result = future.get();
} catch (ExecutionException e) {
throw e.getCause();
}
String accessToken = result.accessToken();
/*
IAuthenticationResult does not contain any method to get the refresh token - how do I get the refresh token??
I want to do something like: result.refreshToken();
*/
IAuthenticationResult is implemented by AuthenticationResult -- but, AuthenticationResult is declared in another class and is not public. AuthenticationResult exposes a method to obtain refreshToken but, I am not able to access it.
Can someone help me access the refresh token?
Thanks!
I got the answer from this link: https://github.com/AzureAD/microsoft-authentication-library-for-java/issues/228
Short Answer: Use reflection
try {
//see com.microsoft.aad.msal4j.AuthenticationResult#refreshToken
final Field refreshTokenField = result.getClass()
.getDeclaredField("refreshToken");
refreshTokenField.setAccessible(true);
return refreshTokenField.get(result).toString();
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
I am working on true SSO in Java application running on Windows 10. My application already has Kerberos auth using Java's GSSAPI (but it obviously does not work on any modern Windows, especially with strict security policies and domain users), so I would like to replace current authorization system with Waffle with minimal implications to overall app design - which I think should be possible if I can get KerberosTicket instance somehow. I am struggling writing this functionality, so far I managed to request some token, but I don't really know what this token is, it does not match Kerberos ticket format. Here is my (actually more like found online code):
public byte[] getServiceTicketSSPI() {
final String securityPackage = "Kerberos";
final String targetName = "<disclosed>";
IWindowsCredentialsHandle clientCredentials = null;
WindowsSecurityContextImpl clientContext = null;
final String currentUser = WindowsAccountImpl.getCurrentUsername();
try {
clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
clientCredentials.initialize();
// initial client security context
clientContext = new WindowsSecurityContextImpl();
clientContext.setPrincipalName(currentUser);
clientContext.setCredentialsHandle(clientCredentials);
clientContext.setSecurityPackage(securityPackage);
final Sspi.SecBufferDesc continueToken = null;
do {
if(debug)
System.out.println("Using target name: " + targetName);
clientContext.initialize(clientContext.getHandle(), continueToken, targetName);
} while(clientContext.isContinue());
return clientContext.getToken();
} finally {
if (clientContext != null)
clientContext.dispose();
if (clientCredentials != null)
clientCredentials.dispose();
}
}
To be fair I am not even sure if SSPI allows me to actually see real ticket. Am I even going in right direction with this snippet? I will be really happy so see any clues as to what should I do. It would be perfect to have KerberosTicket instance in the end.
Below are the steps to do Single Sign On using Waffle for standalone Java Client without using server.
Create client credentials
Get service ticket using initializeSecurityContext of WindowsSecurityContextImpl.
Get WindowsIdentity using accessSecurityContext of WindowsAuthProviderImpl
Original link https://exceptionshub.com/getting-kerberos-service-ticket-using-waffle-in-java.html
For client-server sso, you should follow https://code.dblock.org/2010/04/08/pure-java-waffle.html The code below depicts the standalone java sso using kerberos.
import com.sun.jna.platform.win32.Sspi;
import waffle.windows.auth.IWindowsCredentialsHandle;
import waffle.windows.auth.IWindowsIdentity;
import waffle.windows.auth.IWindowsSecurityContext;
import waffle.windows.auth.impl.WindowsAccountImpl;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;
import waffle.windows.auth.impl.WindowsCredentialsHandleImpl;
import waffle.windows.auth.impl.WindowsSecurityContextImpl;
public class KerberosSingleSignOn {
public static void main() {
try {
System.out.println(getWindowsIdentity().getFqn());
}
catch (Exception e) {
e.printStackTrace();
}
}
public static IWindowsIdentity getWindowsIdentity() throws Exception {
try {
byte[] kerberosToken = getServiceTicketSSPI();
WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl();
IWindowsSecurityContext securityContext = provider
.acceptSecurityToken("client-connection", kerberosToken, "Kerberos");
return securityContext.getIdentity();
}
catch (Exception e) {
throw new Exception("Failed to process kerberos token");
}
}
public static byte[] getServiceTicketSSPI() throws Exception {
final String securityPackage = "Kerberos";
IWindowsCredentialsHandle clientCredentials = null;
WindowsSecurityContextImpl clientContext = null;
final String currentUser = WindowsAccountImpl.getCurrentUsername();
try {
clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
clientCredentials.initialize();
// initial client security context
clientContext = new WindowsSecurityContextImpl();
clientContext.setCredentialsHandle(clientCredentials.getHandle());
/*OR
clientContext.setCredentialsHandle(clientCredentials);
*/
clientContext.setSecurityPackage(securityPackage);
final Sspi.SecBufferDesc continueToken = null;
do {
System.out.println("Using current username: " + currentUser);
clientContext.initialize(clientContext.getHandle(), continueToken, currentUser);
}
while (clientContext.isContinue());
return clientContext.getToken();
}
catch (Exception e) {
throw new Exception("Failed to process kerberos token");
}
finally {
if (clientContext != null)
clientContext.dispose();
if (clientCredentials != null)
clientCredentials.dispose();
}
}
}
I'm trying to send messages to single devices using their token from a Java application. I'm using the Firebase Admin SDK. Below is what I have
FileInputStream serviceAccount = null;
try {
serviceAccount = new FileInputStream("google-services.json");
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
FirebaseOptions options = null;
try {
options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://MYPROJECTID.firebaseio.com/")
.build();
} catch (IOException e1) {
e1.printStackTrace();
}
FirebaseApp.initializeApp(options);
String registrationToken = "MYDEVICETOKEN";
// See documentation on defining a message payload.
Message message = Message.builder().putData("time", "2:45").setToken(registrationToken)
.build();
// Send a message to the device corresponding to the provided
// registration token.
String response = null;
try {
response = FirebaseMessaging.getInstance().sendAsync(message).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);
But I get the following exception
java.io.IOException: Error reading credentials from stream, 'type' field not specified.
What am I doing wrong here?
Click on Generate new private key button.
The error means that your google-services.json file contains invalid data. GoogleCredentials class expects your file to have a type property, but it's not there.
Brief googling gave me this post regarding very similar problem. It says:
From the API Manager, just create select "Create credentials" >
"Service Account key" and generate a new key for the Service
that is associated to your Google Play account.
Architecture: I have a web application from where I'm interacting with the Datastore and a client (raspberry pi) which is calling methods from the web application using Google Cloud Endpoints.
I have to add that I'm not very familiar with web applications and I assume that something's wrong with the setConsumed() method because I can see the call of /create in the app engine dashboard but there's no entry for /setConsumed.
I'm able to add entities to the Datastore using objectify:
//client method
private static void sendSensorData(long index, String serialNumber) throws IOException {
SensorData data = new SensorData();
data.setId(index+1);
data.setSerialNumber(serialNumber);
sensor.create(data).execute();
}
//api method in the web application
#ApiMethod(name = "create", httpMethod = "post")
public SensorData create(SensorData data, User user) {
// check if user is authenticated and authorized
if (user == null) {
log.warning("User is not authenticated");
System.out.println("Trying to authenticate user...");
createUser(user);
// throw new RuntimeException("Authentication required!");
} else if (!Constants.EMAIL_ADDRESS.equals(user.getEmail())) {
log.warning("User is not authorised, email: " + user.getEmail());
throw new RuntimeException("Not authorised!");
}
data.save();
return data;
}
//method in entity class SensorData
public Key<SensorData> save() {
return ofy().save().entity(this).now();
}
However, I'm not able to delete an entity from the datastore using the following code.
EDIT: There are many logs of the create-request in Stackdriver Logging, but none of setConsumed(). So it seems like the calls don't even reach the API although both methods are in the same class.
EDIT 2: The entity gets removed when I invoke the method from the Powershell so the problem is most likely on client side.
//client method
private static void removeSensorData(long index) throws IOException {
sensor.setConsumed(index+1);
}
//api method in the web application
#ApiMethod(name = "setConsumed", httpMethod = "put")
public void setConsumed(#Named("id") Long id, User user) {
// check if user is authenticated and authorized
if (user == null) {
log.warning("User is not authenticated");
System.out.println("Trying to authenticate user...");
createUser(user);
// throw new RuntimeException("Authentication required!");
} else if (!Constants.EMAIL_ADDRESS.equals(user.getEmail())) {
log.warning("User is not authorised, email: " + user.getEmail());
throw new RuntimeException("Not authorised!");
}
Key serialKey = KeyFactory.createKey("SensorData", id);
datastore.delete(serialKey);
}
This is what I follow to delete an entity from datastore.
public boolean deleteEntity(String propertyValue) {
String entityName = "YOUR_ENTITY_NAME";
String gql = "SELECT * FROM "+entityName +" WHERE property= "+propertyValue+"";
Query<Entity> query = Query.newGqlQueryBuilder(Query.ResultType.ENTITY, gql)
.setAllowLiteral(true).build();
try{
QueryResults<Entity> results = ds.run(query);
if (results.hasNext()) {
Entity rs = results.next();
ds.delete(rs.getKey());
return true;
}
return false;
}catch(Exception e){
logger.error(e.getMessage());
return false;
}
}
If you don't want to use literals, you can also use binding as follows:
String gql = "SELECT * FROM "+entityName+" WHERE property1= #prop1 AND property2= #prop2";
Query<Entity> query = Query.newGqlQueryBuilder(Query.ResultType.ENTITY, gql)
.setBinding("prop1", propertyValue1)
.setBinding("prop2", propertyValue2)
.build();
Hope this helps.
I was able to solve it by myself finally!
The problem was just related to the data type of the index used for removeSensorData(long index) which came out of a for-loop and therefore was an Integer instead of a long.
Can someone please explain me how to access the protected web api using a web app client?
I am trying something mentioned here in the following link. But I am always getting
The provided access grant is invalid or malformed.
https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx
Here is the code i am using for java
AuthenticationResult result = null;
try {
final Future<AuthenticationResult> resultFuture = context.acquireTokenByAuthorizationCode(
code, new URI(redirectUri), new ClientCredential(clientId, clientSecret), RESOURCE_GRAPH_API, null);
result = resultFuture.get();
} catch (InterruptedException | ExecutionException e) {
LOG.info("Failed to obtain access token: " + e.getMessage());
} catch (URISyntaxException e) {
}