Currently i am using wso2 api manager 1.9 store , we have a login page before accessing anything in store . it is working fine for now .
Now , there's a requirement that we have a web application on some other domain having the webservice as well to authorize the users , in wso2 api manager store when we login using admin/admin ,, instead of calling its login.jag(for the authorization in wso2 store) , it must be calling that webservice for the authorization and we can use the same credentials as we already using in that web application.
So for this , in login.js (which is called after clicking the login button in store) , i have changed some code like :
ACTUAL CODE
loginbox.login = function (username, password, url,tenant) {
jagg.post("/site/blocks/user/login/ajax/login.jag", { action:"login", username:username, password:password,tenant:tenant },
function (result) {
if (result.error == false) {
if (redirectToHTTPS && redirectToHTTPS != "" && redirectToHTTPS != "{}" &&redirectToHTTPS != "null") {
window.location.href = redirectToHTTPS;
} else if(url){
window.location.href = url;
}else{
window.location.href='site/pages/list-apis.jag';
}
} else {
$('#loginErrorMsg').show();
$('#password').val('');
$('#loginErrorMsg div.theMsg').text(result.message).prepend('<strong>'+i18n.t("errorMsgs.login")+'</strong><br />');
}
}, "json");
CHANGED CODE
loginbox.login = function (username, password, url,tenant) {
$.post(authentication_url,function(result){
if(result.statusCode==200){
//will forward it to list-apis to display the apis
window.location.href='site/pages/list-apis?username=test&password=test&tenant=tenant'
}
});
With this changed code , i am getting the expected response from the webservice which i am calling ,, but not able to keep them in session cookies ,,because before it was calling site/blocks/user/login/ajax/login.jag which will authorize the user and then check for csrf tokens and lot of other things .
Can anyone please let me know where i am missing OR where i need to change so that users from webservice can be authorised .??
Thanks
You cannot pass username and password to /list-api . It does not handle those parameters and set them to session cookie.
window.location.href='site/pages/list-apis?username=test&password=test&tenant=tenant'
I think you might be able to implement something similar to SAML SSO implementation in the api manager. In SAML case, authentication response from the IDP is sent to api manager as a redirection. That request is handled by /store/jagg/jaggery_acs.jag file. Session is set in that location. You might be able to implement similar kind of thing to handle your redirection and set the session there. (I haven't try this)
Related
I'm quite new with identityserver4 so correct me if I say something wrong. I have set up identityserver4 together with ASP Identity for usermanagement and protected my API with it, however I don't know how to get an access token without having to be redirected to the login page. I'm using postman to get an access token via the authorization tab using the following details:
new Client
{
ClientId = "postman-api",
ClientName = "Postman Test Client",
ClientSecrets = { new Secret("PostmanIsASecret".Sha256()) },
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RequireConsent = false,
RedirectUris = { "https://www.getpostman.com/oauth2/callback"},
PostLogoutRedirectUris = { "https://www.getpostman.com" },
AllowedCorsOrigins = { "https://www.getpostman.com" },
EnableLocalLogin = false,
RequirePkce = false,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"jumsum.api"
}
}
I just want to login and get an access token without having to be redirected all the time. In the console I'm getting this:
IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator: Information: Showing login: User is not authenticated
I just want to pass a username and password via the http request body and get an access token back. What am I doing wrong?
You could add a client that accepts the client credentials flow and using this flow you can get an access token using just a username and password. This is a flow for machine-to-machine communication where no human user is involved.
Read more about that here
Identity server is implemented and working well. Google login is working and is returning several claims including email.
Facebook login is working, and my app is live and requests email permissions when a new user logs in.
The problem is that I can't get the email back from the oauth endpoint and I can't seem to find the access_token to manually request user information. All I have is a "code" returned from the facebook login endpoint.
Here's the IdentityServer setup.
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"]
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
Then of course I've customized the AuthenticateLocalAsync method, but the claims I'm receiving only include name. No email claim.
Digging through the source code for identity server, I realized that there are some claims things happening to transform facebook claims, so I extended that class to debug into it and see if it was stripping out any claims, which it's not.
I also watched the http calls with fiddler, and I only see the following (apologies as code formatting doesn't work very good on urls. I tried to format the querystring params one their own lines but it didn't take)
(facebook.com)
/dialog/oauth
?response_type=code
&client_id=xxx
&redirect_uri=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook
&scope=email
&state=xxx
(facebook.com)
/login.php
?skip_api_login=1
&api_key=xxx
&signed_next=1
&next=https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity.[site].com%252Fid%252Fsignin-facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx&cancel_url=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook%3Ferror%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%26state%3Dxxx%23_%3D_
&display=page
&locale=en_US
&logger_id=xxx
(facebook.com)
POST /cookie/consent/?pv=1&dpr=1 HTTP/1.1
(facebook.com)
/login.php
?login_attempt=1
&next=https%3A%2F%2Fwww.facebook.com%2Fv2.7%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fidentity.[site].com%252Fid%252Fsignin-facebook%26state%3Dxxx%26scope%3Demail%26response_type%3Dcode%26client_id%3Dxxx%26ret%3Dlogin%26logger_id%3Dxxx
&lwv=100
(facebook.com)
/v2.7/dialog/oauth
?redirect_uri=https%3A%2F%2Fidentity.[site].com%2Fid%2Fsignin-facebook
&state=xxx
&scope=email
&response_type=code
&client_id=xxx
&ret=login
&logger_id=xxx
&hash=xxx
(identity server)
/id/signin-facebook
?code=xxx
&state=xxx
I saw the code parameter on that last call and thought that maybe I could use the code there to get the access_token from the facebook API https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
However when I tried that I get a message from the API telling me the code has already been used.
I also tried to change the UserInformationEndpoint to the FacebookAuthenticationOptions to force it to ask for the email by appending ?fields=email to the end of the default endpoint location, but that causes identity server to spit out the error "There was an error logging into the external provider. The error message is: access_denied".
I might be able to fix this all if I can change the middleware to send the request with response_type=id_token but I can't figure out how to do that or how to extract that access token when it gets returned in the first place to be able to use the Facebook C# sdk.
So I guess any help or direction at all would be awesome. I've spent countless hours researching and trying to solve the problem. All I need to do is get the email address of the logged-in user via IdentityServer3. Doesn't sound so hard and yet I'm stuck.
I finally figured this out. The answer has something to do with Mitra's comments although neither of those answers quite seemed to fit the bill, so I'm putting another one here. First, you need to request the access_token, not code (authorization code) from Facebook's Authentication endpoint. To do that, set it up like this
var fb = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
SignInAsAuthenticationType = signInAsType,
AppId = ConfigurationManager.AppSettings["Facebook:AppId"],
AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"],
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook"));
return Task.FromResult(0);
}
}
};
fb.Scope.Add("email");
app.UseFacebookAuthentication(fb);
Then, you need to catch the response once it's logged in. I'm using the following file from the IdentityServer3 Samples Repository, which overrides (read, provides functionality) for the methods necessary to log a user in from external sites. From this response, I'm using the C# Facebook SDK with the newly returned access_token claim in the ExternalAuthenticationContext to request the fields I need and add them to the list of claims. Then I can use that information to create/log in the user.
public override async Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx)
{
var externalUser = ctx.ExternalIdentity;
var claimsList = ctx.ExternalIdentity.Claims.ToList();
if (externalUser.Provider == "Facebook")
{
var extraClaims = GetAdditionalFacebookClaims(externalUser.Claims.First(claim => claim.Type == "urn:facebook:access_token"));
claimsList.Add(new Claim("email", extraClaims.First(k => k.Key == "email").Value.ToString()));
claimsList.Add(new Claim("given_name", extraClaims.First(k => k.Key == "first_name").Value.ToString()));
claimsList.Add(new Claim("family_name", extraClaims.First(k => k.Key == "last_name").Value.ToString()));
}
if (externalUser == null)
{
throw new ArgumentNullException("externalUser");
}
var user = await userManager.FindAsync(new Microsoft.AspNet.Identity.UserLoginInfo(externalUser.Provider, externalUser.ProviderId));
if (user == null)
{
ctx.AuthenticateResult = await ProcessNewExternalAccountAsync(externalUser.Provider, externalUser.ProviderId, claimsList);
}
else
{
ctx.AuthenticateResult = await ProcessExistingExternalAccountAsync(user.Id, externalUser.Provider, externalUser.ProviderId, claimsList);
}
}
And that's it! If you have any suggestions for simplifying this process, please let me know. I was going to modify this code to do perform the call to the API from FacebookAuthenticationOptions, but the Events property no longer exists apparently.
Edit: the GetAdditionalFacebookClaims method is simply a method that creates a new FacebookClient given the access token that was pulled out and queries the Facebook API for the other user claims you need. For example, my method looks like this:
protected static JsonObject GetAdditionalFacebookClaims(Claim accessToken)
{
var fb = new FacebookClient(accessToken.Value);
return fb.Get("me", new {fields = new[] {"email", "first_name", "last_name"}}) as JsonObject;
}
I'm building a restricted signup. I want user with a specific code passed in a url to be able to signup and not others. I'm using the accounts package.
I can prevent account creation in the Accounts.onCreateUser method. I'm looking for a way to tell the server if the client had an authorised signup code. With a classic form (email+password) I can just add an extra hidden field. How can I achieve the same result if the user signs up with let's say Facebook?
Since Meteor doesn't use cookies, I can't store this info in a cookie that the server would access. Session variable are not accessible server side. And since I'm not controlling what got send with the account-facebook creation, I can't use a Session variable on the client side that I'd pass along when the user presses sign up.
Any idea"?
Just add the special token to the user object being passed to Accounts.createUser():
var user = {
email: email,
password: password,
profile: {
token: token
}
};
Accounts.createUser(user, function (error, result) {
if (error) {
console.log(error)
}
});
On the server side you can access this in the Accounts.onCreateUser():
Accounts.onCreateUser(function(options, user) {
console.log(options);
console.log(user);
});
I think it's in the options variable that you will find your token, so it would be options.profile.token.
for me, the best option here was passing in custom parameters to loginbuttons.
see the package docs:
https://github.com/ianmartorell/meteor-accounts-ui-bootstrap-3
Where it outlines the below:
accountsUIBootstrap3.setCustomSignupOptions = function() {
return {
mxpDistinctId: Session.get('mxpdid'),
leadSource: Session.get('leadSource')
}
};
I am creating web service using silex micro framework. This is first time i am using it and I dont have prior knowledge on symfony. I could be able to understand how silex works and how to write controller providers , service providers etc ..
I couldnt work out authentication for my webservice.
I want to use JWT authentication and I found this cnam/security-jwt-service-provider extending firebase/php-jwt.
I set it up right and I get this output when I access protected resource
{"message":"A Token was not found in the TokenStorage."}
which is correct.
Question: I want to post the username , password to application and get token back. ( username=admin , password=foo )
I am using postman chrome extension ( also used Advanced rest client ) to post values to url ( http://silex.dev/api/login)
Post data I am sending
Key=> username Value=> admin
Key=> password Value=> foo
I also tried
Key=> _username Value=> admin
Key=> _password Value=> foo
Aldo tried key vaule pairs in basic auth headers.
response I get id
{
"success": false,
"error": "Invalid credentials"
}
When I debug the Application I see no post data at all.
$vars = json_decode($request->getContent(), true);
I get null $var.
PS: I know I will get a valid token back if I get these values posted correctly because I edited values from empty to correct values in breakpoint.
Apparently I should send data in json format and should set content-type appication/json
eg:
{
"_username":"admin",
"_password":"foo"
}
and response will something be like
{
success: true
token: "eyJ0eXAiOisKV1diLCJfbGgiOhJIjzI1NiJ9.eyJuYW1lIjoiYWRtaW4iLCJleHAiOjE0Mzk5MDUxMjh9.DMdXAv2Ay16iI1UQbHZABLCU_gsD_j9-gEU2M2L2MFQ"
}
I'm using Parse.com and trying to set up user sign up with Facebook.
Upon authentication with Facebook for the first time a beforeSave is called on _User to fetch additional user details:
function UserBeforeSave(request, response){
var user = request.object,
auth = user.get('authData');
// check if user is newly registered
if (!user.existed()) {
// Check if a user signs up with facebook
if (Parse.FacebookUtils.isLinked(request.object)) {
// Query Graph API for user details
Parse.Cloud.httpRequest({
url:'https://graph.facebook.com/v2.2/me?access_token=' + auth.facebook.access_token,
success:function(httpResponse){
// Map facebook data to user object
if (httpResponse.data.first_name) request.object.set('first_name', httpResponse.data.first_name);
if (httpResponse.data.last_name) request.object.set('last_name', httpResponse.data.last_name);
if (httpResponse.data.email) request.object.set('email', httpResponse.data.email);
response.success();
},
error:function(httpResponse){
console.error(httpResponse);
response.error();
}
});
} else {
response.success();
}
} else {
response.success();
}
}
Problem is that that email line is actually breaking the operation with error:
Can't modify email in the before save trigger
I tried moving this code to the afterSave but the authdata is not available there making it difficult to call the FB API. The email is therefore left blank at the moment.
I'm assuming this is a very common use case of integrating Parse with the Facebook API, am I missing something in the integration process that automatically fetches the email?
I just do the graph query client-side and set email there. This works fine.
Is there a reason you want to do it in the before/afterSave on the User?