I am trying to connect to Microsoft Share Point from my Java application. The documentation for Microsoft Graph SDK for Java is not so clear.
I am trying to initiate the Graph client, while providing the credentials needed via a custom GUI or configuration file.
I am trying to do as follow but can
IGraphServiceClient client = GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
I need the "authenticationProvider" object to be of a class implementing IAuthenticationProvider, however its not clear what parameters to add or how to create this object. Has anyone tried this before and what is the correct way to build the client and provide the required credentials?
Microsoft has an example project where they have a simple instance of IAuthenticationProvider.
public class SimpleAuthProvider implements IAuthenticationProvider {
private String accessToken = null;
public SimpleAuthProvider(String accessToken) {
this.accessToken = accessToken;
}
#Override
public void authenticateRequest(IHttpRequest request) {
// Add the access token in the Authorization header
request.addHeader("Authorization", "Bearer " + accessToken);
}
}
The AuthenticationProviders that implement a variety of different OAuth flows are available in a seperate package. See this Github repo here:
https://github.com/microsoftgraph/msgraph-sdk-java-auth
Related
I'm trying to implement multi-factor authentication (mfa) with spring oauth2. I have my own authorization server and I'm trying to follow this guide https://sultanov.dev/blog/multi-factor-authentication-with-spring-boot-and-oauth2. I made two custom granter CustomePasswordTokenGranter and MFATokenGranter. CustomePasswordTokenGranter will return access_token with authority pre_auth to be used with MFATokenGranter later.
CustomPasswordTokenGranter -> username, password -> Oauth2AccessToken(authorities = [PRE_AUTH])
MFATokenGranter -> access_token -> do I need to check wheter it contains PRE_AUTH or not?
public class MfaTokenGranter extends AbstractTokenGranter {
#Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
// do I need this line of code?
if(!client.getAuthorities().contains(PRE_AUTH)) {
throw new InvalidAuthorityException();
}
}
}
btw I'm not sure if I have to check authority of a client that trying to access this granter. I want the token that was generated from CustomePasswordTokenGranter to be used with MfaTokenGranter only. Does spring automatically check that for me or I have to do it my own or it doesn't matter if I check it or not?
I've created an API using AWS API Gateway. All of the methods used in the API require IAM authentication.
I tried to test the API locally and got the following exception:
myapi.model.MyAPIException: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1632)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1304)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1058)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649)
at com.amazonaws.client.ClientHandlerImpl.doInvoke(ClientHandlerImpl.java:204)
at com.amazonaws.client.ClientHandlerImpl.invoke(ClientHandlerImpl.java:185)
at com.amazonaws.client.ClientHandlerImpl.execute(ClientHandlerImpl.java:93)
at com.amazonaws.opensdk.protect.client.SdkClientHandler.execute(SdkClientHandler.java:42)
at myapi.MyAPIClient.myMethod(MyAPIClient.java:101)
...
For building the request I used the following code:
public static void main(String[] args) {
MyAPI client = MyAPI .builder()
.apiKey(myApiKey)
.iamCredentials(DefaultAWSCredentialsProviderChain.getInstance())
.build();
MyMethodRequest myMethodRequest = new MyMethodRequest().arg(methodArg);
MyMethodResult result = client.myMethod(myMethodRequest);
}
The credentials loaded by the DefaultAWSCredentialsProviderChain are my credentials which have admin access to all of my AWS services so I'm not sure what is wrong.
Any help is appreciated.
The problem ended being having entered the wrong apiKey for the API.
When I changed it to a valid API key generated by API Gateway everything worked.
Also, you have to make sure the API Key is linked to a valid usage plan or it will not work
Usually class more like:
package ...;
public class ListingMusic implements
RequestHandler<HashMap<String, Object>, String> {
#Override
public String handleRequest(HashMap<String, Object> input, Context context) {
...
}
}
Maybe it can be that your lambda can't start
I am having trouble grasping the idea of authorization in PlayFramework (version 2.5). My situation is I have a REST API method getUser and I want to restrict its access by performing authorization with a token that is coming in custom request header named "X-Authorization". Now my controller code looks like that:
package controllers;
import models.User;
import org.bson.types.ObjectId;
import play.mvc.*;
import org.json.simple.*;
import views.html.*;
public class ApiController extends Controller {
public Result getUser(String userId) {
User user = User.findById(new ObjectId(userId));
JSONObject userG = new JSONObject();
//Some code to append data to userG before return
return ok(userG.toJSONString());
}
}
The route URL is defined like this:
GET /api/user/:id controllers.ApiController.getUser(id)
Option 1 could be to check the Authorization token inside the method getUser and also check for other credentials but I want to restrict access before even it get calls getUser method. As in future I will be adding more method calls to this REST API. So I will be reusing the same authorization to those future REST APIs as well.
I found there is authorization available in Play Framework which I am not able to understand. I tried to implement Authorization by extending class Security.Authenticator and overriding methods getUserName and onUnauthorized like this:
package controllers;
import models.Site;
import models.User;
import org.json.simple.JSONObject;
import play.mvc.Http.Context;
import play.mvc.Result;
import play.mvc.Security;
public class Secured extends Security.Authenticator {
#Override
public String getUsername(Context ctx) {
String auth_key = ctx.request().getHeader("X-Authorization");
Site site = Site.fineByAccessKey(auth_key);
if (site != null && auth_key.equals(site.access_key)) {
return auth_key;
} else {
return null;
}
}
#Override
public Result onUnauthorized(Context ctx) {
JSONObject errorAuth = new JSONObject();
errorAuth.put("status", "error");
errorAuth.put("msg", "You are not authorized to access the API");
return unauthorized(errorAuth.toJSONString());
}
}
Then I've appended the annotation to the getUser method with #Security.Authenticated(Secured.class). It works fine and returns unauthorized error. But now I am not sure if that is the preferred way. I feel this is not the right way to do it as the name of the override of function getUsername suggests that too. I am not checking for any username in session or cookie rather only the token present in the header of request.
Also I know there is a module named Deadbolt which is used for authorization but I read its documents and I am not able to integrate it. It was relatively complex integration for a beginner like me. I was confused about how to use it. I thought about using SubjectPresent controller authorization but still I was not able to implement it successfully.
In the end what do you guys suggest that should I use Security.Authenticator the way I have implemented? Or do you suggest that I go to my first option that is checking authorization inside getUser method? Or Anyone can tell me how to implement Deadbolt in my scenario?
You are mixing Authorization and Authentication.
Here is a good thread: Authentication versus Authorization
I like this answer:
Authentication = login + password (who you are)
Authorization = permissions (what you are allowed to do)
Authentication == Authorization (excluding anonymous user) if you allow doing something for all users that you know (i.e. Authenticated users)
The main goal of Deadbolt is Authorization (already Authenticated users). Your main goal is Authentication.
I would advise you to use Pac4J, it Authentication library not only for Play, and it has versions as for Java as for Scala. There is a good sample project: https://github.com/pac4j/play-pac4j-java-demo
I use this library myself in my projects and the task
As in future i will be adding more method calls to this REST api. So i
will be reusing the same authorization to those future REST apis as
well.
I solve as easy as just add the configuration in the 'application.conf`:
pac4j.security {
rules = [
{"/admin/.*" = {
authorizers = "ADMIN"
clients = "FormClient"
}}
]
}
Just do not forget to add Security filter. This feature present in the example project, so just clone and try.
Another example form the official page:
pac4j.security.rules = [
# Admin pages need a special authorizer and do not support login via Twitter.
{"/admin/.*" = {
authorizers = "admin"
clients = "FormClient"
}}
# Rules for the REST services. These don't specify a client and will return 401
# when not authenticated.
{"/restservices/.*" = {
authorizers = "_authenticated_"
}}
# The login page needs to be publicly accessible.
{"/login.html" = {
authorizers = "_anonymous_"
}}
# 'Catch all' rule to make sure the whole application stays secure.
{".*" = {
authorizers = "_authenticated_"
clients = "FormClient,TwitterClient"
}}
]
I followed the instructions to create a custom security realm for my glassfish. It all works fine, users are authenticated correctly. The problem however is the following:
The user credentials are encrypted in a string
The realm decrypts this string and performs the authentication against a database (works)
Instead of using the decrypted values as principal in the securityContext the encrypted
String is passed.
I already tried to override the commit() method to replace the _userPrincipal or attach my own implementation using getSubject().getPrincipals().add(new PrincipalImpl("user")). Neither was working as expected. Basically the question is a simple as this: How can I set my own principal in a custom security realm in glassfish in a way which makes it possible to use it together with an injected securityContext?
My environment:
Glassfish 3.1.2.2 (Build 5) Full Profile
The application running behind the authentication is a JAX-RS 1.1 based application
The SecurityContext is obtained using injection
I already tried to override the commit() method to replace the
_userPrincipal or attach my own implementation using getSubject().getPrincipals().add(new PrincipalImpl("user")). Neither
was working as expected.
What kind of error(s) do you get?
Regardless, I think your issue lies on the third step of this process. SecurityContext only defines BASIC_AUTH, FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH as AuthenticationScheme so perhaps SecurityContext cannot see your implementation of your security scheme or type. But you can try these steps and I hope they would work for you.
A- Implement a Java Authentication and Authorization Service (JAAS) LoginModule or extend com.sun.appserv.security.AppservPasswordLoginModule
public class MyLoginModule extends AppservPasswordLoginModule {
#Override
protected void authenticateUser() throws LoginException {
if (!authenticate(_username, _password)) {
//Login fails
throw new LoginException("LoginFailed");
}
String[] myGroups = getGroupNames(_username);
commitUserAuthentication(myGroups);
}
private boolean authenticate(String username, String password) {
/*
Check the credentials against the authentication source, return true if authenticated, return false otherwise
*/
return true;
}
private String[] getGroupNames(String username) {
// Return the list of groups this user belongs to.
}
B- Implementing your realm class.
public class MyRealm extends AppservRealm {
#Override
public void init(Properties props)
throws BadRealmException, NoSuchRealmException {
//here you initialize the realm
}
#Override
public String getAuthType() {
return "Custom Realm";
}
}
C- Installing and configuring the realm and LoginModule into the server.
for this you need to look at JSR 196 and write you own SAM by implmenting javax.security.auth.message.module.ServerAuthModule. Take a look at thelink below.
https://blogs.oracle.com/enterprisetechtips/entry/adding_authentication_mechanisms_to_the
We're using Restlet 2.0.8 and have an Application instance overwriting org.restlet.Application#createInboundRoot(). In there, we create the Router instance and return (at the moment) a DigestAuthenticator, like in the code snipped below:
#Override
public synchronized Restlet createInboundRoot() {
log.info("App::createInboundRoot called");
this.authenticator = getAuthenticator();
Router router = new Router(getContext());
router.attach("/echo", EchoResource.class);
router.attach("/status", StatusResource.class);
authenticator.setNext(router);
return authenticator;
}
private ChallengeAuthenticator getAuthenticator() {
DigestAuthenticator auth = new DigestAuthenticator(getContext(), "Guard", "s3cret");
auth.setWrappedVerifier(new SimpleVerifier("user","pass");
auth.setOptional(false);
return auth;
}
What I would like to achieve is:
have the EchoResource using digest authentication and the StatusResource should use HTTP basic authentication
Is this possible with Restlets?
Best,
Chris
This is possible by chaining the DigestAuthenticator (optional: true) and the BasicAuthenticator (optional: false). Pseudo-code:
digestAuth.setNext(basicAuth);
basicAuth.setNext(router);
In a similar situation, we created two org.restlet.Application objects, require authentication for one Application as in the question above, and did attach both the Applications to different paths in the Servlet container.