Claim rules reference previous claims in ADFS? - saml

I'm having trouble getting ADFS to send claim to my app. The authentication is now completing successfully, but none of the claims we've set in rules are being sent with the response. I have two rules in this order.
In the first rule, my understanding is the types section is whatever my application is expecting ADFS to output, and doesn't need to correspond to LDAP values. What is really important is the query which must reference valid LDAP attributes. I am sure the query values are valid LDAP attributes, as another working Relying Party configuration uses these same query values(but they use different values in types for output).
In the second rule, I am referencing Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier". This is not a type in LDAP, but is a reference to the claim created in the first rule. Am I doing that correctly? Can the second rule reference an output type from the first rule?
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types =
("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"),
query = ";givenName,sn,mail,employeeI;{0}", param = c.Value);
Second rule
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/namequalifier"] = "http://somedomain.com/adfs/services/trust",
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/spnamequalifier"] = "https://someapp.somedomain.com/sp");
Also, is there any reason ADFS wouldn't send claims if the Relying Party is not setup with a certificate for encryption(it is using the IDP certificate to generate signatures/validate)?

The usual reason claims are not sent is that those AD attributes are null.
You can't use the same claim as input / output.
Take nameidentifier out of the first claim, have a separate claim which outputs something like http://company.com/temp and which is an add not an issue.
Then use http://company.com/temp as input to the second claim with output http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier.

Related

Importing azurerm_linux_virtual_machine resource - Error: Value for unconfigurable attribute

I imported my existing azurerm_linux_virtual_machine in terraform state file and notice that now terraform plan is removing the identity block. Then I added the identity block in my terraform code with attributes plan was removing
identity {
identity_ids = []
principal_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
tenant_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
type = "SystemAssigned"
}
and now its complaining
Error: Value for unconfigurable attribute
Can't configure a value for "identity.principal_id": its value will be decided automatically based on the result of applying this configuration.
Error: Value for unconfigurable attribute
Can't configure a value for "identity.tenant_id": its value will be decided automatically based on the result of applying this configuration.
Can someone please help? I also tried with different type like "UserAssigned" but that is not helping either.
The meaning of these messages is that those two attributes of the identity object type are chosen by the provider rather than being chosen by you in the configuration. Providers typically declare attributes in this way if they are something that the remote API decides in its response, rather than something the client decides in the request.
If your goal is to make the configuration match the object you imported into the state then you need only to set the attributes that are considered by the provider to be arguments chosen in the configuration, which in this case seems to be just identity_ids and type and so you could write the following:
identity {
identity_ids = []
type = "SystemAssigned"
}
As part of the producing the plan, Terraform will try to merge the arguments you specified in the configuration with the attributes already in the state and so should therefore be able to produce an identity object that matches the one already in the Terraform state, and thus avoid proposing to make a change.

ABAC with keycloak - Using Resource attributes in policy

What I am trying to achieve
Protect a resource in Keycloak with policy like:
if (resource.status == 'draft') $evaluation.grant();
else $evaluation.deny();
Going by their official documents and mailing list responses, it seems attribute based access control is possible, however, I could not find a way of getting it to work.
What I have tried
Using Authorization Services: I was unable to figure out where and how I can inject the attributes from the resource instance.
Using Authorization Context: I was hoping to get the policies associated with a resource and a scope so that I could evaluate them my self.
So far, I have managed to get no where with both approaches. To be honest, I have been overwhelmed by the terminology used in the Authorization services.
Question
How can I use attributes of a resource instance while defining a policy in keycloak?
I solved this problem in Keycloak 4.3 by creating a JavaScript policy because Attribute policies don't exist (yet). Here is an example of the code I got working (note that the attribute values are a list, so you have to compare against the first item in the list):
var permission = $evaluation.getPermission();
var resource = permission.getResource();
var attributes = resource.getAttributes();
if (attributes.status !== null && attributes.status[0] == "draft") {
$evaluation.grant();
} else {
$evaluation.deny();
}
Currently there is no way to do what you are looking to do. ResourceRepresentation class only has (id, name, uri, type, iconUri, owner) fields. So you can use owner to determine ownership per Keycloak example. I've seen a thread that talks about adding additional resource attributes, but haven't seen a Keycloak JIRA for it.
Perhaps you could use Contextual Attributes in some way by setting what you need at runtime and writing a Policy around it.
var context = $evaluation.getContext();
var attributes = context.getAttributes();
var fooValue = attributes.getValue("fooAttribute");
if (fooValue.equals("something"))
{
$evaluation.grant();
}

How to deal with anonymous login attempts when you allow both anonymous access and logged in users?

I have a framework that allows anonymous access as well as named user accounts. I'm exposing an OData resource on a certain URL. When configured as such, anonymous users can see parts of the resource and logged in users (through basic authentication) can see more.
The problem I'm facing is that some OData clients (like Excel) will initially attempt to access the OData resource anonymously even when you do provide credentials. Only when this fails, they will use the provided credentials. My understanding is that this is because there are many ways to log in and some clients just always try the most basic option first. But this prevents them from ever actually seeing more data, because they never use the provided credentials and also never get the authentication challenge when the resource allows anonymous access.
Is there a way to solve this issue, allowing both anonymous access AND properly sending an authentication challenge when possible? Is there maybe some header that clients will send when they do have credentials but just aren't supplying them initially?
Some (scala) code to make this a bit more tangible:
val (username, password) = getAuthInfo(request)
if (username != null && password != null) {
val regularSession = integration.core.login(username, password)
logger.debug(s"Login OK: User '$username' (Number of concurrent sessions: ${integration.core.getNumberConcurrentSessions}).")
(IMxRuntimeResponse.OK, null, regularSession)
} else if (integration.configuration.getEnableGuestLogin) {
val guestSession = integration.core.initializeGuestSession
logger.debug(s"Anonymous user '${guestSession.getUser.getName}' created " +
"(Number of concurrent sessions: ${integration.core.getNumberConcurrentSessions}).")
(IMxRuntimeResponse.OK, null, guestSession)
} else {
val responseMessage = "No basic authentication in header."
logger.warn(s"Login failed: $responseMessage")
(IMxRuntimeResponse.UNAUTHORIZED, responseMessage, null)
}
Somewhere else outside the surrounding try/catch:
if (httpStatusCode == IMxRuntimeResponse.UNAUTHORIZED)
response.addHeader("WWW-Authenticate", "Basic")
As you can see the challenge is never sent when anonymous access is allowed.
Edit: we investigated and there does not seem to be anything special in the headers of this request that would indicate this is an initial attempt that will result in another request when an authentication challenge is sent, rather than just another anonymous login attempt. We are at a loss here now on how to proceed.

What is the difference between PSCredentialUIOptions.Default and PSCredentialUIOptions.ValidateUserNameSyntax?

One of the overloads in PowerShell for the $Host.UI.PromptForCredential method has an options parameter, which is a bitwise combination of PSCredentialUIOptions values.
Looking at MSDN for PSCredentialUIOptions I find the enum values include:
Default : Validates the user name, but not its existence or
correctness.
and
ValidateUserNameSyntax : Validates the syntax of the user name, but
not its existence or correctness.
What exactly do these descriptions mean?
For Default, when it validates the user name, does it mean it just checks the user has entered something, anything, in the User Name field of the PSCredentials dialog?
And for ValidateUserNameSyntax, how does it validate the syntax of the user name? By checking for illegal characters in the entered text?
I've tried Googling for more information but all links just lead back to the MSDN page or the identical TechNet page.
Not only does ValidateUserNameSyntax check for illegal characters, but it also validates the format of the username against the allowedCredentialTypes you supply to PromptForCredential():
$PromptCaption = "Creds plz!"
$PromptMessage = "Please input your domain credentials"
$CredentialType = [System.Management.Automation.PSCredentialTypes]::Domain
$ValidateOption = [System.Management.Automation.PSCredentialUIOptions]::ValidateUserNameSyntax
$Host.UI.PromptForCredential($PromptCaption,$PromptMessage,"","",$CredentialType,$ValidateOption)

Perl Net::LDAP - Fetch DN without Search?

I have the DN of the LDAP entry. I know I could search for it: Doing something like this:
my $search = $ldap->search(
base => $dn,
scope => "base",
filter => "(objectclass=*)",
);
But, I don't need to do a search. I have the DN. I simply want to pull up the DN entry and do my operations directly on that. Something like this:
my $dn_entry = $ldap->get( $dn );
Is there a method to get the DN entry from the DN string itself, or do you have to search for the entry even if you know the DN itself?
Using LDAP, clients must always search or use an extended operation to get data. If you're interested in all the attributes associated with an entry, and the DN is known, use the following parameters in a search request:
baseObject: the DN that is known
search scope: base
filter: either (&) or (objectClass=*)
the list of attributes to be returned. Some APIs use * for all user attributes and + for all operational attributes.
What it sounds like you are saying is that you have stored the "Distinguished Name" (a string) rather than the DN entry (a Net::LDAP::Entry object). If this is the case, I believe you have to create a new Net::LDAP::Entry object from the DN. The documentation indicates that you can apply operations directly to such an object without synchronizing with the server, but this won't supply all the data for the given DN. If you need the server's data, you need to get it via $ldap->search(...).
Have you considered using the Net::LDAP::LDIF mechanism for storing DN data locally?