Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I don't see anything in the documentation on how to:
connect to LDAP and
set controls for user access based on AD Group.
LDAP/Active Directory
LdapAuthenticationSource is an implementation of external authentication to make users login with their LDAP (active directory) user name and password.
If we want to use LDAP authentication, we first add Abp.Zero.Ldap nuget package to our project (generally to Core (domain) project). Then we should extend LdapAuthenticationSource for our application as shown below:
public class MyLdapAuthenticationSource : LdapAuthenticationSource<Tenant, User>
{
public MyLdapAuthenticationSource(ILdapSettings settings, IAbpZeroLdapModuleConfig ldapModuleConfig)
: base(settings, ldapModuleConfig)
{
}
}
Lastly, we should set a module dependency to AbpZeroLdapModule and enable LDAP with the auth source created above:
[DependsOn(typeof(AbpZeroLdapModule))]
public class MyApplicationCoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Modules.ZeroLdap().Enable(typeof (MyLdapAuthenticationSource));
}
...
}
After these steps, LDAP module will be enabled for your application. But LDAP auth is not enabled by default. We can enable it using settings.
Settings
LdapSettingNames class defines constants for setting names. You can use these constant names while changing settings (or getting settings). LDAP settings are per tenant (for multi-tenant applications). So, different tenants have different settings (see setting definitions on github).
As you can see in the MyLdapAuthenticationSource constructor, LdapAuthenticationSource expects ILdapSettings as a constructor argument. This interface is used to get LDAP settings like domain, user name and password to connect to Active Directory. Default implementation (LdapSettings class) gets these settings from the setting manager.
If you work with Setting manager, then no problem. You can change LDAP settings using setting manager API. If you want, you can add an initial/seed data to database to enable LDAP auth by default.
Note: If you don't define domain, username and password, LDAP authentication works for current domain if your application runs in a domain with appropriate privileges.
Custom Settings
If you want to define another setting source, you can implement a custom ILdapSettings class as shown below:
public class MyLdapSettings : ILdapSettings
{
public async Task<bool> GetIsEnabled(int? tenantId)
{
return true;
}
public async Task<ContextType> GetContextType(int? tenantId)
{
return ContextType.Domain;
}
public async Task<string> GetContainer(int? tenantId)
{
return null;
}
public async Task<string> GetDomain(int? tenantId)
{
return null;
}
public async Task<string> GetUserName(int? tenantId)
{
return null;
}
public async Task<string> GetPassword(int? tenantId)
{
return null;
}
}
And register it to IOC in PreInitialize of your module:
[DependsOn(typeof(AbpZeroLdapModule))]
public class MyApplicationCoreModule : AbpModule
{
public override void PreInitialize()
{
IocManager.Register<ILdapSettings, MyLdapSettings>(); //change default setting source
Configuration.Modules.ZeroLdap().Enable(typeof (MyLdapAuthenticationSource));
}
...
}
Then you can get LDAP settings from any other source.
https://aspnetboilerplate.com/Pages/Documents/Zero/User-Management#ldapactive-directory
Related
I am creating an authentication and authorization handler for internal authorization purposes. My intention is to make it easy for my colleagues to implement the solution into their own projects. We are using Azure AD for authentication, and for authorization we are using Azure Groups. In order to do that, I feel like I am stuck on figuring out how to add authorization policies in an efficient way.
Right now I'm adding it through the officially described way in the Program class of my Client project in a Blazor webassembly hosted configuration:
builder.Services.AddAuthorizationCore(options =>
options.AddPolicy("PolicyName", policy =>
{
policy.RequireClaim("ClaimType", "ClaimValue");
})
);
This works fine, but it's not intuitive, as any given project could require several different policies
I have also added a custom Authorization Policy Provider, as described in this documentation from Microsoft:
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-6.0
I figured this would be what I was looking for, based on their description for this documentation, especially the first couple of lines in the documentation. But I still can't seem to get it to work as intended, without specifically adding each policy manually.
If need be I can show my custom implementation of the Authorization Policy Provider, but it is pretty much exactly as seen in the Github for the documentation.
Policies are most commonly registered at application startup in the Startup classes ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(config =>
{
config.AddPolicy("IsDeveloper", policy => policy.RequireClaim("IsDeveloper","true"));
});
}
the policy IsDeveloper requires that a user have the claim IsDeveloper with a value of true.
Roles you can apply policies via the Authorize attribute.
[Route("api/[controller]")]
[ApiController]
public class SystemController
{
[Authorize(Policy = “IsDeveloper”)]
public IActionResult LoadDebugInfo()
{
// ...
}
}
Blazors directives and components also work with policies.
#page "/debug"
#attribute [Authorize(Policy = "IsDeveloper")]
< AuthorizeView Policy="IsDeveloper">
< p>You can only see this if you satisfy the IsDeveloper policy.< /p>
< /AuthorizeView>
Easier Management
With role-based auth, if we had a couple of roles which were allowed access to protected resources - let’s say admin and moderator. We would need to go to every area they were permitted access and add an Authorize attribute.
[Authorize(Roles = "admin,moderator")]
This doesn’t seem too bad initially, but what if a new requirement comes in and a third role, superuser, needs the same access? We now need to go round every area and update all of the roles. With policy-based auth we can avoid this.
We can define a policy in a single place and then apply it once to all the resources which require it. Then when extra roles need to be added, we can just update the policy from the central point without the need to update the individual resources.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(config =>
{
config.AddPolicy("IsAdmin", policy => policy.RequireRole("admin", "moderator", "superuser"));
});
}
[Authorize(Policy = "IsAdmin")]
Creating shared policies
We need to install the Microsoft.AspNetCore.Authorization package from NuGet in order to do this.
After that create a new class called Policies with the following code.
public static class Policies
{
public const string IsAdmin = "IsAdmin";
public const string IsUser = "IsUser";
public static AuthorizationPolicy IsAdminPolicy()
{
return new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
.RequireRole("Admin")
.Build();
}
public static AuthorizationPolicy IsUserPolicy()
{
return new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
.RequireRole("User")
.Build();
}
}
Here we’re using the AuthorizationPolicyBuilder to define each policy, both require the user to be authenticated then be in either the Admin role or User role, depending on the policy.
Configuring the server
Rregistering the policies in ConfigureServices in the Startup class. Add the following code under the existing call to AddAuthentication.
services.AddAuthorization(config =>
{
config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
});
registering each policy and using the constants we defined in the Policies class to declare their names, which saves using magic strings.
If we move over to the SampleDataController we can update the Authorize attribute to use the new IsAdmin policy instead of the old role.
[Authorize(Policy = Policies.IsAdmin)]
[Route("api/[controller]")]
public class SampleDataController : Controller
Again, we can use our name constant to avoid the magic strings.
Configuring the client
Our server is now using the new policies we defined, all that’s left to do is to swap over our Blazor client to use them as well.
As with the server we’ll start by registering the policies in ConfigureServices in the Startup class. We already have a call to AddAuthorizationCore so we just need to update it.
services.AddAuthorizationCore(config =>
{
config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
});
In Index.razor, update the AuthorizeView component to use policies - still avoiding the magic strings.
< AuthorizeView Policy="#Policies.IsUser">
< p>You can only see this if you satisfy the IsUser policy.< /p>
< /AuthorizeView>
< AuthorizeView Policy="#Policies.IsAdmin">
< p>You can only see this if you satisfy the IsAdmin policy.< /p>
< /AuthorizeView>
Finally, update FetchData.razors Authorize attribute.
#attribute [Authorize(Policy = Policies.IsAdmin)]
Refer here
I'm using Spring Security, and want to be able to run with a "local" profile with security off. I can do this by using a profile-controlled WebSecurityConfigurerAdapter which allows anonymous access, but the problem is that any Principal or Authentication arguments to controller methods are null.
The way I've solved this before is by passing the arguments through an adapter, which has a non-local pass-through implementation and a "local"-profile implementation that substitutes a configured value:
#GetMapping()
public ResponseEntity<List<Thing>> getThings(Principal principal) {
Principal myPrincipal = securityAdapter.principal(principal);
...
}
But this feels really clunky. Is there some way to configure Spring Security to make the substitution so that I can keep the code clean?
Unfortunately it is a SpringSecurity feature: the AnonymousAuthenticationToken is not injected in controller methods. I could find some references for that in this issue.
A possible workaround (from above issue) is to inject a custom trust resolver that pretends that the AnonymousAuthenticationToken is not anonymous...
#Bean
public AuthenticationTrustResolver trustResolver() {
return new AuthenticationTrustResolver() {
#Override
public boolean isRememberMe(final Authentication authentication) {
return false;
}
#Override
public boolean isAnonymous(final Authentication authentication) {
return false;
}
};
}
Rather ugly, but as it is intended to run in a profile where anonymous authentication is expected to be valid, it could be enough.
I have two services within the same project:
[Authenticate]
public class OnlyDoesBasicAuth : Service
{
}
[Authenticate]
public class OnlyDoesJwtAuth : Service
{
}
//AppHost
public override void Configure(Container container)
{
Plugins.Add(new AuthFeature(
() => new AuthUserSession(),
new IAuthProvider[]
{
new BasicAuthProvider(AppSettings),
new JwtAuthProvider(AppSettings)
}
)
{
HtmlRedirect = null
});
}
The way this is set up, I can get into both services using Basic Authentication or with a valid Bearer token. I'd prefer to have it so that only one service can do one means of authentication. Is there a way to specify with provider to use on authentication?
I'm at a loss on how to approach this. I was thinking that maybe there was a way via global request filter or something to that effect, but maybe that's not the way to go. I could split the project into two projects, which will definitely work, but it's not the way I want to approach it.
I'm just looking for a way for the OnlyDoesBasicAuth to only use the BasicAuthProvider on authentication and OnlyDoesJwtAuth to only use the JwtAuthProvider within the same project. Any and all suggestions will be greatly appreciated.
Thanks in advance.
Typically once you're authenticated using any of the Auth Providers you're considered as an Authenticated User everywhere in ServiceStack.
You can restrict access so that a Service needs to be Authenticated with by specifying the AuthProvider name in the [Authenticate] attribute, e.g:
[Authenticate(BasicAuthProvider.Name)]
public class OnlyDoesBasicAuth : Service
{
}
[Authenticate(JwtAuthProvider.Name)]
public class OnlyDoesJwtAuth : Service
{
}
Alternatively you can validate within your Service that they need to be authenticated with a specific Auth Provider, e.g:
if (SessionAs<AuthUserSession>().AuthProvider != JwtAuthProvider.Name)
throw HttpError.Forbidden("JWT Required");
I have a WCF service that is defined in a module. When we try to call this service from a non-default tenant, the content manager always references our default tenants settings. In debugging, inside of OrchardServiceHostFactory,
I notice that it ends up getting the settings for the default tenant because the base address that is passed into the CreateServiceHost method is always our default tenants uri.
Given that I am not wholly familiar with WCF, is there a configuration option that I am missing that is causing the WCF service to be created with the default tenants address, instead of the non-default tenant?
Relevant code:
private static readonly Route _SITEMAP_SERVICE_ROUTE = new ServiceRoute("api/SitemapService", new OrchardServiceHostFactory(), typeof(ISitemapService))
{
DataTokens = new RouteValueDictionary
{
{
"area", "Project.Localization"
}
}
};
public interface ISitemapService : IOrchardSitemapService, IDependency
{
}
[ServiceContract]
public interface IOrchardSitemapService
{
[OperationContract]
int GetNavigableContentCount();
[OperationContract]
List<SitemapEntry> GetNavigableContent();
}
I was able to fix this by adding an additional site to IIS that pointed to the same file system location, and used the same application pool. This new site then references the non-default's tenant, and the service will now be created with the correct base address.
i´m trying to add some authentication and authorization functionality to my small web application. therefore i´m using apache shiro.
my plan: using an existing ldap server for user authentication and using a properties or ini file for authorization.
here´s a small example:
user x wants to use the application
he enters his username and his password
the ldap server is used for authentication --> user + pwd correct?
if authentication is verified and correct, a properties file or ini file is used to check if the user is permitted, to start some functions inside the application.
i hope you know what i´m trying to do.
now i´m not sure how to implement this feature. is it enough to use an ini file or is it required to implement my own realm?! is there an example implementation?
i´m grateful for every information
and sorry for my bad english :/
Yes, you have to implement a realm but this is not difficult. You just have to extend JndiLdapRealm and override the queryForAuthorizationInfo method.
This method returns an AuthorizationInfo interface type. In your case the easiest is to return an instance of SimpleAuthorizationInfo which implements this interface.
You must initialize the AuthorizationInfo with the roles and/or permissions for the authenticated user. When this method is called, the user is already authenticated but not authorized.
Inside this method you can read the authorization information from any data source that you want, it can be a properties or ini file, properties associated with the user in the LDAP server, a database or anything that pleases you.
A realm implementation could be:
package example.shiro.realm.ldap;
import javax.naming.NamingException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.realm.ldap.LdapContextFactory;
import org.apache.shiro.subject.PrincipalCollection;
public class JndiLdapAuthzRealm extends JndiLdapRealm {
private List<String> getRoles(String userName) {
List<String> roles = new ArrayList<>();
// TODO: get roles from data source and fill list
roles.add("user");
roles.add("admin");
return roles;
}
private List<String> getPermissions(String userName) {
List<String> perms = new ArrayList<>();
// TODO: get permissions from data source and fill list
perms.add("myapp:run");
perms.add("myapp:file:create");
return perms;
}
#Override
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
String userName = principals.getPrimaryPrincipal().toString();
info.addRoles(getRoles(userName));
info.addStringPermissions(getPermissions(userName));
return info;
}
}
In your case, rewrite the getRoles and getPermissions to get the roles and permissions for the authenticated user from the properties or ini file.
In shiro.ini:
[main]
ldapRealm = example.shiro.realm.ldap.JndiLdapAuthzRealm
ldapRealm.userDnTemplate = uid={0},cn=users,cn=accounts,dc=example,dc=com
ldapRealm.contextFactory.url = ldap://192.168.0.10