how to skip facebook app permissions dialog - asp.net

Here, I am trying to authenticate user via login and after that I want to skip permissions dialog. But I am unable to achieve this, as it always asking for permissions for app to the user. My intention is if user is not logged into the facebook he/she should be prompted for facebook login and then I will fetch public information by using method Get("/me"). Let me know what I am doing wrong here.
public string GetFBAccessToken(string strAppID, string strAppSecret, string strUrl)
{
// Declaring facebook client type
var vFB = new FacebookClient();
string strAccessTok = string.Empty;
try
{
if (!string.IsNullOrEmpty(strAppID) && !string.IsNullOrEmpty(strAppSecret) && !string.IsNullOrEmpty(strUrl))
{
// Getting login url for facebook
var loginUrl = vFB.GetLoginUrl(new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
response_type = "code",
state = "returnUrl",
//scope = "",
display = "popup"
});
// Redirecting the page to login url
if (HttpContext.Current.Request.QueryString["code"] == null)
{
HttpContext.Current.Response.Redirect(loginUrl.AbsoluteUri);
}
// Fetching the access token from query string
if (HttpContext.Current.Request.QueryString["code"] != null)
{
dynamic result = vFB.Post("oauth/access_token", new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
code = HttpContext.Current.Request.QueryString["code"]
});
// Getting access token and storing in a variable
strAccessTok = result.access_token;
}
}
return strAccessTok;
}
catch (Exception ex)
{
//if (HttpContext.Current.Request.QueryString["response_type"] == "code")
//{
// var fb = new FacebookClient();
// var details = fb.Get("/me");
//}
return strAccessTok;
}
}

Regardless to the platform/ language you are using; solution can be as follows.
check use's logged in status. https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
based on Response status, forcefully call your action (i.e. Log in, Get Permission or any additional action if user is already connected). For Log in check this reference document from FB. https://developers.facebook.com/docs/facebook-login/login-flow-for-web/

No. You cannot skip the Login Dialog.
In fact, it is really important for an APP owner to build a trust relationship with your users. I would recommend you to follow the Login Best Practices while authenticating the users using your APP.

Related

Not able to create event for room resource calendar

I have set up a google service account with Domain-wide delegation permissions. I am using Google Calendar APIs to manage the calendar events. Here is the sample code snippet:
InputStream inputstream = null;
try {
inputstream = new ByteArrayInputStream(this.key);
Credential cred = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setServiceAccountId(cs.getGoogleServiceAccountId())
.setServiceAccountScopes(Arrays.asList(CalendarScopes.CALENDAR))
.setServiceAccountUser("c_188d28jockafkhljibdpn05gio6iq#resource.calendar.google.com")
.setServiceAccountPrivateKey(SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(),
inputstream,"notasecret",
"privatekey", "notasecret"))
.build();
calendar = new Calendar.Builder(new NetHttpTransport(), new JacksonFactory(), cred).setApplicationName("applicationName").build();
Event e = new Event().setSummary("Test");
e.setDescription("Test");
e.setStart(new EventDateTime().setDateTime(new DateTime(new Date().getTime())));
e.setStart(new EventDateTime().setDateTime(new DateTime(DateUtils.addHours(new Date(), 1).getTime())));
Event insert = calendar.events().insert("c_188d28jockafkhljibdpn05gio6iq#resource.calendar.google.com", e).setSendNotifications(true).execute();
logger.info("event created = {}", JsonUtil.getJSONString(insert));
}
finally {
if(inputstream != null) {
inputstream.close();
}
}
It gives the following exception when I try to create an event in the room resource calendar:
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{
"error" : "invalid_grant",
"error_description" : "Invalid email or User ID"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:326)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:346)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:397)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:494)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:880)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:541)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:474)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:591)
It works fine when I try to create an event in any active user's calendar by replacing the resource email id with a particular user's email. What could be the issue?

Asp.net core & Identity server: External logins not working

I've set up an asp.net core (2.1) application using asp.net identity and plugged in Identity Server 4 as the auth middleware. This is working well for local accounts, but now I'm trying to enable 3rd party login providers, starting with Google.
So I added the following to my ConfigureServices method:
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "numbershere.apps.googleusercontent.com";
options.ClientSecret = "my-secret";
});
And added the UI scaffolding in to the project and my Google Sign In button appears. If I click it, I get redirected to Google, log in and get presented with the confirmation screen before being returned to my app.
At this point, OnGetCallbackAsync of my ExternalLoginModel is being hit, which contains a call:
var info = await _signInManager.GetExternalLoginInfoAsync();
However, info is always null after this call and the user is therefore just redirected back to the login page:
public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (remoteError != null)
{
ErrorMessage = $"Error from external provider: {remoteError}";
return RedirectToPage("./Login", new {ReturnUrl = returnUrl });
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
}
I've read about online and even followed the points in the Identity Server quick start, but can't see what I've missed.
Can anyone advise what I've not done/configured to make this work?
Thanks

Can we add users to keycloak in realms other than 'master'?

I can add users to keycloak but only in the master realm. Is there a way to add users to other realms beside master?
I tried and received an HTTP 401 Unauthorized Exception.
Sounds like your user doesn't have the manage-users role in other realms.
Just go to the admin realm, look up your user, navigate to Role mappings tab, then in the Client Roles drop down select the correct realm and then add manage-users as a role. Repeat for all realms.
//Here's how I created a user to my realm using Java
#Override
public UserDto registerNewUserAccount(final UserDto accountDto) {
String keycloakPassword = accountDto.getPassword();
accountDto.setPassword(passwordEncoder.encode(accountDto.getPassword()));
accountDto.setEnabled(1);
UserDto user = userRepository.save(accountDto);
AuthorityDto role = new AuthorityDto();
role.setUserName(accountDto.getLogin());
role.setAuthority("ROLE_USER");
authorityRepository.save(role);
Keycloak kc = Keycloak.getInstance(
"https://www.zdslogic.com/keycloak/auth", /your server
"zdslogic", //your realm
"richard.campion", //user
"Changit", //password
"admin-cli"); //client
CredentialRepresentation credential = new CredentialRepresentation();
credential.setType(CredentialRepresentation.PASSWORD);
credential.setValue(keycloakPassword);
UserRepresentation keycloakUser = new UserRepresentation();
keycloakUser.setUsername(accountDto.getLogin());
keycloakUser.setFirstName(accountDto.getFirstName());
keycloakUser.setLastName(accountDto.getLastName());
keycloakUser.setEmail(accountDto.getEmail());
keycloakUser.setCredentials(Arrays.asList(credential));
keycloakUser.setEnabled(true);
keycloakUser.setRealmRoles(Arrays.asList("user"));
// Get realm
RealmResource realmResource = kc.realm("zdslogic");
UsersResource usersRessource = realmResource.users();
// Create Keycloak user
Response result = null;
try {
result = usersRessource.create(keycloakUser);
} catch(Exception e) {
System.out.println(e);
}
if (result==null || result.getStatus() != 201) {
System.err.println("Couldn't create Keycloak user.");
}else{
System.out.println("Keycloak user created.... verify in keycloak!");
}
return user;
}

Is there any possibility return the access_token with only user object?

I am implementing a functionality, where access_token will be sent via email, in this case I need to generate this token with a logic to authenticate the user when accessing the link passed via email.
public async Task<IActionResult> GetLink ()
{
var user = await userManager.FindByEmailAsync("eduardo#test.com.br"); // is active user created
if (user != null)
{
var ident = await userManager.GetAuthenticationTokenAsync(user, "Test", "access_token");
return Ok(ident);
}
return NoContent();
}
Based on the research expected would be something like this, but this is not done with persisted data and my model is not allowing this, anyone have any idea how to persist? Or even just return the token?
I think it is a bad behavior not is not acceptable, but, my user dont have a password for access in this case, maybe is necessary using the token or another mode to login.
It is a very simple flow, this link would be one for a granted action (it will only have read access, basically), and this link will be sent only to a user via email.
The above problem can be solved as follows:
[HttpGet("get_token")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetUserToken([FromServices] ITokenService TS, [FromServices] IUserClaimsPrincipalFactory<EkyteUser> principalFactory,
[FromServices] IdentityServerOptions options)
{
var Request = new TokenCreationRequest();
var user = await userManager.FindByIdAsync(User.GetSubjectId());
var IdentityPricipal = await principalFactory.CreateAsync(user);
var IdServerPrincipal = IdentityServerPrincipal.Create(user.Id.ToString(), user.UserName);
Request.Subject = IdServerPrincipal;
Request.IncludeAllIdentityClaims = true;
Request.ValidatedRequest = new ValidatedRequest();
Request.ValidatedRequest.Subject = Request.Subject;
Request.ValidatedRequest.SetClient(Config.GetClient());
Request.Resources = new Resources(Config.GetResources(), Config.GetApiResources());
Request.ValidatedRequest.Options = options;
var Token = await TS.CreateAccessTokenAsync(Request);
Token.Issuer = "http://" + HttpContext.Request.Host.Value;
var TokenValue = await TS.CreateSecurityTokenAsync(Token);
return Ok(TokenValue);
}
It is necessary to identify the user, set the necessary resources and consequently the client that is accessing. After that, just include the access host to generate the token.

Can IUserMapper be used to Change User Details

In Nancy FX how can I use the IUserMapper (if at all) to change a logged in users account details (name, email, password)?
// registering is straight forward
Post["/register", true] = async(parameters, ct) =>
{
var user = this.BindAndValidate<UserRegistration>();
var response = await mapper.RegisterUser(user); // user is registered
...
}
// but how can I change a registered user's details?
Post["/profile", true] = async(parameters, ct) =>
{
this.RequiresAuthenticationAndLogOut();
var user = this.BindAndValidate<UserRegistration>();
var response = await mapper.?????(user);
...
}
You wouldn't use the IUserMapper at all, this really only exists for authentication purposes and nothing more.
When a user is authenticated then you get access to the UserName property. If you setup your mapper to assign the user's Id to the UserName then you can load your user, modify, and commit.
i.e:
Post["/profile", true] = async(parameters, ct) =>
{
this.RequiresAuthenticationAndLogOut();
var user = this.BindAndValidate<UserRegistration>();
var existingUser = await db.LoadAsync(int.Parse(CurrentUser.UserName));
existingUser.Name = user.Name;
...
return ...;
}
Also, you should never persist an object that's been bound from a client. The user may submit additional information you don't want them to.
Also I don't know where you got your IUserMapper from because in Nancy there is no Register.

Resources