How can I send the federated authenticator as a claim to my service provider ?
The SP wants to know which one has been used to authenticate the subject. Is there a local IS claim to send back to the SP ?
I already know about Always send back the authenticated list of identity providers but I need a claim to send.
Thanks in advance.
You can write a custom claim handler that handles the claim mapping and deploy it into IS server. You can follow this document and create a custom claim handler https://docs.wso2.com/display/IS580/Writing+a+Custom+Claim+Handler. You can get the federatedIdpName from the AuthneticatedUser object [1].
A sample code is given below.
public Map<String, String> handleClaimMappings(StepConfig stepConfig,
AuthenticationContext context, Map<String, String> remoteAttributes,
boolean isFederatedClaims) throws FrameworkException {
String authenticatedUser = null;
if (stepConfig != null) {
//calling from StepBasedSequenceHandler
authenticatedUser = stepConfig.getAuthenticatedUser();
} else {
//calling from RequestPathBasedSequenceHandler
authenticatedUser = context.getSequenceConfig().getAuthenticatedUser();
}
Map<String, String> claims = handleExternalClaims(authenticatedUser);
return claims;
}
private Map<String, String> handleExternalClaims(AuthenticatedUser authenticatedUser) throws FrameworkException {
Map<String, String> externalClaims = new HashMap<String, String>();
externalClaims.put("http://test.org/claims/idpName", authenticatedUser.getFederatedIdPName());
return externalClaims;
}
[1]https://github.com/wso2/carbon-identity-framework/blob/master/components/authentication-framework/org.wso2.carbon.identity.application.authentication.framework/src/main/java/org/wso2/carbon/identity/application/authentication/framework/model/AuthenticatedUser.java#L49
Related
public class UserRegistrationCustomEventHandler extends AbstractEventHandler {
JSONObject jsonObject = null;
private static final Log log = LogFactory.getLog(UserRegistrationCustomEventHandler.class);
#Override
public String getName() {
return "customClaimUpdate";
}
if (IdentityEventConstants.Event.POST_SET_USER_CLAIMS.equals(event.getEventName())) {
String tenantDomain = (String) event.getEventProperties()
.get(IdentityEventConstants.EventProperty.TENANT_DOMAIN);
String userName = (String) event.getEventProperties().get(IdentityEventConstants.EventProperty.USER_NAME);
Map<String, Object> eventProperties = event.getEventProperties();
String eventName = event.getEventName();
UserStoreManager userStoreManager = (UserStoreManager) eventProperties.get(IdentityEventConstants.EventProperty.USER_STORE_MANAGER);
// String userStoreDomain = UserCoreUtil.getDomainName(userStoreManager.getRealmConfiguration());
#SuppressWarnings("unchecked")
Map<String, String> claimValues = (Map<String, String>) eventProperties.get(IdentityEventConstants.EventProperty
.USER_CLAIMS);
String emailId = claimValues.get("http://wso2.org/claims/emailaddress");
userName = "USERS/"+userName;
JSONObject json = new JSONObject();
json.put("userName",userName );
json.put("emailId",emailId );
log.info("JSON:::::::"+json);
// Sample API
//String apiValue = "http://192.168.1.X:8080/SomeService/user/updateUserEmail?email=sujith#gmail.com&userName=USERS/sujith";
try {
URL url = new URL(cityAppUrl) ;
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5000);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
log.info("CONN:::::::::::::"+con);
OutputStream os = con.getOutputStream();
os.write(cityAppUrl.toString().getBytes("UTF-8"));
os.close();
InputStream in = new BufferedInputStream(con.getInputStream());
String result = org.apache.commons.io.IOUtils.toString(in, "UTF-8");
jsonObject = new JSONObject(result);
log.info("JSON OBJECT:::::::::"+jsonObject);
}
catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void init(InitConfig configuration) throws IdentityRuntimeException {
super.init(configuration);
}
#Override
public int getPriority(MessageContext messageContext) {
return 250;
}
}
I'm using wso2 identity server 5.10.0 and have to push the updated claim value to an API so I'm using a custom handler and have subscribed to POST_SET_USER_CLAIMS, i have to read the API value from deployment.toml file in jave code of the custom handler. So can any one please help here to read the value from deployment file
I can fetch the updated claim value in logs but im not able to get the API value. So can anyone help me here to read the value from deployment file.
Since the API path is required inside your custom event handler, let's define the API path value as one of the properties of the event handler.
Add the deployment.toml config as follows.
[[event_handler]]
name= "UserRegistrationCustomEventHandler"
subscriptions =["POST_SET_USER_CLAIMS"]
properties.apiPath = "http://192.168.1.X:8080/SomeService/user/updateUserEmail"
Once you restart the server identity-event.properties file populates the given configs.
In your custom event handler java code needs to read the config from identity-event.properties file. The file reading is done at the server startup and every config is loaded to the memory.
By adding this to your java code, you can load to configured value in the property.
configs.getModuleProperties().getProperty("UserRegistrationCustomEventHandler.apiPath")
NOTE: property name needs to be defined as <event_handler_name>.<property_name>
Here is a reference to such event hanlder's property loading code snippet https://github.com/wso2-extensions/identity-governance/blob/68e3f2d5e246b6a75f48e314ee1019230c662b55/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/handler/PasswordPolicyValidationHandler.java#L128-L133
I am trying to update my appsync client to authenticate with IAM credentials. In case of API_KEY I set the API_KEY_HEADER like so: request.addHeader(API_KEY_HEADER, this.apiKey); Is there a similar way to authenticate in a Java client with IAM credentials? Is there a header I can pass in to pass in the secret and access keys like here: https://docs.amplify.aws/lib/graphqlapi/authz/q/platform/js#iam? Or should I just be using a cognito user pool as a way to authenticate the request?
According to AWS Documentation we need to use sign requests using the process documented here: https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html and steps listed here: https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html.
I also found an implementation here: https://medium.com/#tridibbolar/aws-lambda-as-an-appsync-client-fbb0c1ce927d. Using the code above:
private void signRequest(final Request<AmazonWebServiceRequest> request) {
final AWS4Signer signer = new AWS4Signer();
signer.setRegionName(this.region);
signer.setServiceName("appsync");
signer.sign(request, this.appsyncCredentials);
}
private Request<AmazonWebServiceRequest> getRequest(final String data) {
final Request<AmazonWebServiceRequest> request =
new DefaultRequest<AmazonWebServiceRequest>("appsync");
request.setHttpMethod(HttpMethodName.POST);
request.setEndpoint(URI.create(this.appSyncEndpoint));
final byte[] byteArray = data.getBytes(Charset.forName("UTF-8"));
request.setContent(new ByteArrayInputStream(byteArray));
request.addHeader(AUTH_TYPE_HEADER, AWS_IAM_AUTH_TYPE);
request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_GRAPHQL);
request.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(byteArray.length));
signRequest(request);
return request;
}
private HttpResponseHandler<String> getResponseHandler() {
final HttpResponseHandler<String> responseHandler = new HttpResponseHandler<String>() {
#Override
public String handle(com.amazonaws.http.HttpResponse httpResponse) throws Exception {
final String result = IOUtils.toString(httpResponse.getContent());
if(httpResponse.getStatusCode() != HttpStatus.SC_OK) {
final String errorText = String.format(
"Error posting request. Response status code was %s and text was %s. ",
httpResponse.getStatusCode(),
httpResponse.getStatusText());
throw new RuntimeException(errorText);
} else {
final ObjectMapper objectMapper = new ObjectMapper();
//custom class to parse appsync response.
final AppsyncResponse response = objectMapper.readValue(result, AppsyncResponse.class);
if(CollectionUtils.isNotEmpty(response.getErrors())){
final String errorMessages = response
.getErrors()
.stream()
.map(Error::getMessage)
.collect(Collectors.joining("\n"));
final String errorText = String.format(
"Error posting appsync request. Errors were %s. ",
errorMessages);
throw new RuntimeException(errorText);
}
}
return result;
}
#Override
public boolean needsConnectionLeftOpen() {
return false;
}
};
return responseHandler;
}
private Response<String> makeGraphQlRequest(final Request<AmazonWebServiceRequest> request) {
return this.httpClient.requestExecutionBuilder()
.executionContext(new ExecutionContext())
.request(request)
.execute(getResponseHandler());
}
I am trying to retrieve images from my bucket to send to my mobile apps, I currently have the devices accessing AWS directly, however I am adding a layer of security and having my apps (IOS and Android) now make requests to my server which will then respond with DynamoDB and S3 data.
I am trying to follow the documentation and code samples provided by AWS for .Net and they worked seamlessly for DynamoDB, I am running into problems with S3.
S3 .NET Documentation
My problem is that if I provide no credentials, I get the error:
Failed to retrieve credentials from EC2 Instance Metadata Service
This is expected as I have IAM roles set up and only want my apps and this server (in the future, only this server) to have access to the buckets.
But when I provide the credentials, the same way I provided credentials for DynamoDB, my server waits forever and doesn't receive any responses from AWS.
Here is my C#:
<%# WebHandler Language="C#" Class="CheckaraRequestHandler" %>
using System;
using System.Web;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using System.IO;
using System.Threading.Tasks;
public class CheckaraRequestHandler : IHttpHandler
{
private const string bucketName = "MY_BUCKET_NAME";
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USEast1;
public static IAmazonS3 client = new AmazonS3Client("MY_ACCESS_KEY", "MY_SECRET_KEY", RegionEndpoint.USEast1);
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod.ToString() == "GET")
{
string userID = context.Request.QueryString["User"];
string Action = context.Request.QueryString["Action"];
if (userID == null)
{
context.Response.ContentType = "text/plain";
context.Response.Write("TRY AGAIN!");
return;
}
if (Action == "GetPhoto")
{
ReadObjectDataAsync(userID).Wait();
}
var client = new AmazonDynamoDBClient("MY_ACCESS_KEY", "MY_SECRET_KEY", RegionEndpoint.USEast1);
Console.WriteLine("Getting list of tables");
var table = Table.LoadTable(client, "TABLE_NAME");
var item = table.GetItem(userID);
if (item != null)
{
context.Response.ContentType = "application/json";
context.Response.Write(item.ToJson());
}
else
{
context.Response.ContentType = "text/plain";
context.Response.Write("0");
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
static async Task ReadObjectDataAsync(string userID)
{
string responseBody = "";
try
{
string formattedKey = userID + "/" + userID + "_PROFILEPHOTO.jpeg";
//string formattedKey = userID + "_PROFILEPHOTO.jpeg";
//formattedKey = formattedKey.Replace(":", "%3A");
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucketName,
Key = formattedKey
};
using (GetObjectResponse response = await client.GetObjectAsync(request))
using (Stream responseStream = response.ResponseStream)
using (StreamReader reader = new StreamReader(responseStream))
{
string title = response.Metadata["x-amz-meta-title"]; // Assume you have "title" as medata added to the object.
string contentType = response.Headers["Content-Type"];
Console.WriteLine("Object metadata, Title: {0}", title);
Console.WriteLine("Content type: {0}", contentType);
responseBody = reader.ReadToEnd(); // Now you process the response body.
}
}
catch (AmazonS3Exception e)
{
Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
}
}
}
When I debug, this line waits forever:
using (GetObjectResponse response = await client.GetObjectAsync(request))
This is the same line that throws the credentials error when I don't provide them. Is there something that I am missing here?
Any help would be greatly appreciated.
I suspect that the AWS .NET SDK has some isses with it specifically with the async call to S3.
The async call to dynamoDB works perfect, but the S3 one hangs forever.
What fixed my problem was simply removing the async functionality (even tho in the AWS docs, the async call is supposed to be used)
Before:
using (GetObjectResponse response = await client.GetObjectAsync(request))
After:
using (GetObjectResponse response = myClient.GetObject(request))
Hopefully this helps anyone else encountering this issue.
I have a website which exposes an ODatas $metadata but to do anything further requires the request to be authenticated (using a cookie).
I want to access this from a console app, not a browser.
I am using Microsofts Odata V4 client code generator.
1) Create a wrapper around the provided Container created by the OData client code generator.
2) Log in and get the cookie you need for authentication
3) Add a hook to the request builder, so you can apply cookies at request time. For my app, I specifically needed the cookie with the name .AspNet.ApplicationCookie
Here is a full working example. You can instantiate this container with the user and password needed as defined at the bottom. This MUST match whatever the controller at the Login API is expecting.
using Nito.AsyncEx;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace MyAppOdataOdataService.Default
{
public class MyAppOdataContainer : Container
{
public Cookie[] _MyAppOdataAuthcookie;
public string cookieAuthName = ".AspNet.ApplicationCookie";
private string baseurl = "https://TheAppwWebsite.co.jp/";
public MyAppOdataContainer(MyAppOdataLoginInfo logininfo ) :
base(new Uri("https://TheAppwWebsite.co.jp/odata/"))
{
// init authorization
_MyAppOdataAuthcookie = AsyncContext.Run(() => AuthenticateUser(logininfo));
if (_MyAppOdataAuthcookie == null) throw new UnauthorizedAccessException();
this.BuildingRequest += AddCookie;
}
private void AddCookie(object sender, Microsoft.OData.Client.BuildingRequestEventArgs e)
{
e.Headers.Add("Cookie", cookieAuthName+"=" + _MyAppOdataAuthcookie.First(c=>c.Name == cookieAuthName).Value);
}
private async Task<Cookie[]> AuthenticateUser(MyAppOdataLoginInfo logininfo)
{
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(baseurl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Uri uri = new Uri(baseurl + "/Login/Login");
HttpResponseMessage response = await client.PostAsJsonAsync(uri, logininfo);
response.EnsureSuccessStatusCode();
// Return the URI of the created resource.
return cookies.GetCookies(uri).Cast<Cookie>().ToArray();
}
}
public class MyAppOdataLoginInfo
{
public string Username { get; set; }
public string Password { get; set; }
}
}
Thanks:
How to apply the cookie:
Creating the client code:
CookieContainer explaination:
Post operation idea here - for authorizing - having to use PostAsJsonAsync
I am trying to write a SOLR client using SolrJ HttpSolrClient.
I have to use Basic Authentication.
The documentation for SolrJ HttpSolrClient says that there is:
protected ModifiableSolrParams invariantParams
and the description is:
Parameters that are added to every request regardless. This may be a place to add something like an authentication token.
Can someone who has used this before please tell me how to use the invariantParams for basic auth?
public class MySolrClient extends HttpSolrClient{
private String hostUrl;
private String userName;
private String password;
public CloudForgeProcurementSolrClient(final String hostUrl, final String userName, final String password) {
super(hostUrl);
this.hostUrl = hostUrl;
this.userName = userName;
this.password = password;
if (invariantParams == null) {
invariantParams = new ModifiableSolrParams();
}
// invariantParams.add(arg0, arg1);
}
}
What should be arg0 and arg1 be in my case.
Thanks in advance!
You can do something like
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
"myusername","mypassword");
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpSolrClient solrClient = new HttpSolrClient(solrCoreUrl, client);
you can use below code:
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new
UsernamePasswordCredentials(username,password);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpSolrClient solrClient = new HttpSolrClient.Builder()
.withBaseSolrUrl(host)
.withHttpClient(client).build();