There are two users: ManagerOne and ManagerTwo. Before use my service they must login.
public class MyService : IMyService
{
int _userID = -1;
public bool LogIn(int userID, string password)
{
if( UserCheck(userID, password) )
_userID = userID;
else
throw new FaultException<InvalidUserFault>(new InvalidUserFault());
}
}
After login they can run GetSome() operation. This operation return some my DataContract. And this operation can run only ManagerOne. If ManagerTworun GetSome(), operation must return error. The question is: what is best practice - return OperationResult<T> or FaultException (in THIS scenario)?
See some code:
public class MyService : IMyService
{
int _userID = -1;
public bool LogIn(int userID, string password){...}
public OperationResult<SomeDataContract> GetSome()
{
if(_userID != 101)
return new OperationResult<SomeDataContract>()
{
Result = false,
ResultMessage = "User hasn't permission",
ReturnValue = null;
};
.....
}
}
Or:
public class MyService : IMyService
{
int _userID = -1;
public bool LogIn(int userID, string password){...}
public SomeDataContract GetSome()
{
if(_userID != 101)
throw new FaultException<MyFaultContract>(new MyFaultContract("User hasn't permission"));
}
}
In classic app I would use GenericResult, because I think it is not exception. But what about WCF? Is FaultException normal practice for my scenario?
Related
Every time I close the browser I need to log in again into this app. It is developed in .NET Core 2.0. I'm trying to let it logged in, like every other regular site.
I checked this post that may be useful, but since the code is quite different from this application I decided to create this post.
This is my security code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
namespace Petito.Common
{
public interface IActivityContext
{
string ActivityID { get; }
IPrincipal User { get; }
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityIdentity : IIdentity
{
private string _name = null;
[JsonIgnore()]
private bool _isAuthenticated = false;
[JsonIgnore()]
private string _authenticationType = "";
public ActivityIdentity()
{
}
public ActivityIdentity(string name) : this(name, false, "")
{
}
internal ActivityIdentity(string name, bool isAuthenticated, string authenticationType)
{
this._name = name;
this._isAuthenticated = isAuthenticated;
this._authenticationType = authenticationType;
}
public string Name { get => _name; }
public bool IsAuthenticated { get => _isAuthenticated; }
public string AuthenticationType { get => _authenticationType; }
public static ActivityIdentity Unathenticated => new ActivityIdentity();
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityPrincipal : IPrincipal
{
private ActivityIdentity _activityIdentity = null;
private string[] _roles = null;
public ActivityPrincipal() : this(ActivityIdentity.Unathenticated, null)
{
}
public ActivityPrincipal(ActivityIdentity activityIdentity, params string[] roles)
{
_activityIdentity = activityIdentity;
_roles = roles;
}
public ActivityIdentity Identity => _activityIdentity;
IIdentity IPrincipal.Identity => _activityIdentity;
public bool IsInRole(string role)
{
if (_roles != null && _roles.Length > 0)
{
return _roles.Contains(role);
}
return false;
}
}
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class ActivityContext : IDisposable, IActivityContext
{
private string _activityID = Guid.NewGuid().ToString();
private DateTime _startDate = DateTime.UtcNow;
private DateTime? _endDate = null;
private ActivityPrincipal _activityPrincipal = null;
public ActivityContext() : this(null)
{
}
public ActivityContext(IPrincipal principal)
{
_activityPrincipal = Convert(principal);
}
private ActivityPrincipal Convert(IPrincipal principal)
{
if (principal == null)
{
return new ActivityPrincipal();
}
var activityPrincipal = principal as ActivityPrincipal;
if (activityPrincipal != null)
{
return activityPrincipal;
}
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal != null)
{
var roles = claimsPrincipal.Claims.Select(x => x.Value);
var p = new ActivityPrincipal(
new ActivityIdentity(claimsPrincipal.Identity.Name, claimsPrincipal.Identity.IsAuthenticated, claimsPrincipal.Identity.AuthenticationType)
, roles.ToArray()
);
return p;
}
throw new NotSupportedException($"Converting {principal.GetType()} not supported");
}
public void Dispose()
{
if (!_endDate.HasValue)
{
_endDate = DateTime.UtcNow;
}
}
public string ActivityID { get => _activityID; }
public DateTime StartDate { get => _startDate; }
public DateTime? EndDate { get => _endDate; }
public IPrincipal User
{
get
{
return _activityPrincipal;
}
}
}
}
Of course, I'll still try to figure out what's wrong with the code. Please if you need another part of the code other from that I posted let me know.
Thanks!
I am using the opened connect middleware to authenticate with a third party oidc provider and everything is up and running as I would expect. During the token exchange I exchange my auth code for an access token which is successful but I then need to store this bearer token for use later in subsequent requests. The token exchange is done as part of my startup class (by overriding the OpenIdConnectEvents during the OnAuthorizationCodeReceived method) in the asp.net core project and I need to store and access that token in my controllers.
As there is no “session” per se yet, what is the most effective (or recommended way) to store this token value from the startup class and make it accessible in my controllers?
Ive tried to use IMemoryCache but despite putting the value in the cache during this startup phase, when I try and access that cache in my controller, it is always empty.
Is there a better/preferred way of persisting values form the startup class for later use in the lifecycle?
I can see in HttpContext.Authentication.HttpAuthenticationFeature.Handler.Options I have access to all the OpenIdConnectOptions properties and settings for oidc, but nowhere can I see the actual token value that I stored after the token exchange.
I use a similar approach with Auth0 and JWT. I store some app_metadata on the claims server, retrieve, and use these values in my controllers for every request.
Startup.cs Configure
var options = new JwtBearerOptions
{
Audience = AppSettings.Auth0ClientID,
Authority = AppSettings.Auth0Domain
};
app.UseJwtBearerAuthentication(options);
app.UseClaimsTransformation(new ClaimsTransformationOptions
{
Transformer = new Auth0ClaimsTransformer()
});
AdminClaimType
public abstract class AdminClaimType : Enumeration
{
public static readonly AdminClaimType AccountId = new AccountIdType();
public static readonly AdminClaimType ClientId = new ClientIdType();
public static readonly AdminClaimType IsActive = new IsActiveType();
private AdminClaimType(int value, string displayName) : base(value, displayName)
{
}
public abstract string Auth0Key { get; }
public abstract string DefaultValue { get; }
private class AccountIdType : AdminClaimType
{
public AccountIdType() : base(1, "AccountId")
{
}
public override string Auth0Key => "accountId";
public override string DefaultValue => "0";
}
private class ClientIdType : AdminClaimType
{
public ClientIdType() : base(2, "ClientId")
{
}
public override string Auth0Key => "clientId";
public override string DefaultValue => "0";
}
private class IsActiveType : AdminClaimType
{
public IsActiveType() : base(3, "IsActive")
{
}
public override string Auth0Key => "isActive";
public override string DefaultValue => "false";
}
}
Auth0ClaimsTransformer
public class Auth0ClaimsTransformer : IClaimsTransformer
{
private string _accountId = AdminClaimType.AccountId.DefaultValue;
private string _clientId = AdminClaimType.ClientId.DefaultValue;
private string _isActive = AdminClaimType.IsActive.DefaultValue;
public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
//TODO: Clean up and simplify AdminClaimTypes Transformer
foreach (var claim in context.Principal.Claims)
{
switch (claim.Type)
{
case "accountId":
_accountId = claim.Value ?? _accountId;
break;
case "clientId":
_clientId = claim.Value ?? _clientId;
break;
case "isActive":
_isActive = claim.Value ?? _isActive;
break;
}
}
((ClaimsIdentity)context.Principal.Identity)
.AddClaims(new Claim[]
{
new Claim(AdminClaimType.AccountId.DisplayName, _accountId),
new Claim(AdminClaimType.ClientId.DisplayName, _clientId),
new Claim(AdminClaimType.IsActive.DisplayName, _isActive)
});
return Task.FromResult(context.Principal);
}
BaseAdminController
//[Authorize]
[ServiceFilter(typeof(ApiExceptionFilter))]
[Route("api/admin/[controller]")]
public class BaseAdminController : Controller
{
private long _accountId;
private long _clientId;
private bool _isActive;
protected long AccountId
{
get
{
var claim = GetClaim(AdminClaimType.AccountId);
if (claim == null)
return 0;
long.TryParse(claim.Value, out _accountId);
return _accountId;
}
}
public long ClientId
{
get
{
var claim = GetClaim(AdminClaimType.ClientId);
if (claim == null)
return 0;
long.TryParse(claim.Value, out _clientId);
return _clientId;
}
}
public bool IsActive
{
get
{
var claim = GetClaim(AdminClaimType.IsActive);
if (claim == null)
return false;
bool.TryParse(claim.Value, out _isActive);
return _isActive;
}
}
public string Auth0UserId
{
get
{
var claim = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
return claim == null ? string.Empty : claim.Value;
}
}
private Claim GetClaim(AdminClaimType claim)
{
return User.Claims.FirstOrDefault(x => x.Type == claim.DisplayName);
}
}
Now in my controller classes that inherit from BaseAdminController I have access to:
AccountId
ClientId
IsActive
Auth0UserId
Anything else I want to add
Hope this helps.
So I figured it out. It is available on HttpContext via the AuthenticationManager:
var idToken = ((AuthenticateInfo)HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies").Result).Properties.Items[".Token.id_token"];
Works a treat :)
In my exploration of JPA, I have the code below (which I understand should not be used in production). Running my code produces the following error:
java.lang.IllegalStateException:
Exception Description: Cannot use an EntityTransaction while using JTA.
The Resource code is as follows:
#Path("users")
public class UsersAPI {
#Context
UriInfo uriInfo;
#Inject
UserBean accountsBean;
#GET
#Path("deduplicate")
public Response deduplicateDB(){
List<UserProfile> profiles = accountsBean.getAll();
int profilesNum = profiles.size();
for(int i = 0; i < profilesNum; ++i){
for(int k = 0; k < profilesNum; ++k){
if(i != k){ //if it's not the same profile
if(profiles.get(i).getUsername().equals(profiles.get(k).getUsername())){
accountsBean.remove(profiles.get(k));
profiles.remove(k);
}
}
profilesNum = profiles.size();
}
}
return Response.ok().build();
}
}
The code in the ProfilesBean is as follows:
#Local
#Stateless
public class UserBean {
#PersistenceContext
EntityManager eManager;
public void save(UserProfile data){
eManager.merge(data);
}
public void remove(UserProfile data){
eManager.getTransaction().begin();
eManager.remove(data);
eManager.getTransaction().commit();
}
public List<UserProfile> getAll(){
Query q = eManager.createQuery("SELECT profile FROM Users profile");
return (List<UserProfile>)q.getResultList();
}
}
Here is the code for the Entity class:
#Entity(name="Users")
public class UserProfile {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long id;
String password;
#Column(unique=true)
String username;
public UserProfile(String username){
setUsername(username);
}
public UserProfile(){
this(null);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
It seems like the error comes from my misusing the platform somehow. How can I fix this code and not misuse the platform in the future?
If you are using JTA as transaction-type in persistence.xml file just leave JTA handles your transactions
public void remove(UserProfile data){
eManager.remove(eManager.merge(data));
}
UPDATE:
In a more clear solution you could use "find", but you need to provide the object id
public void remove(UserProfile data){
UserProfile e = em.find(UserProfile.class, data.getId());
eManager.remove(e);
}
I have created a custom authentication provider that checks if a user exists in a datasource and allows it to login or not.
Now I also have to check the roles of that user, but I don't understand if the same provider can take care of Authentication and Role mapping or if I have to do another provider.
I had tried to created another provider, for the role mapping, but I can't find it, or not looking in the right place to configurate it, but my MBean type also doesn't any configs to be inserted.
Can anyone help me with this?
I tried to find examples of role mapping, with no luck.
Thanks
Have a look at the Oracle Guide: How to Develop a Custom Role Mapping Provider
The process is very similiar to creating an authentication Provider, the only difference are the interfaces you have to implement.
Now for my Implementation (I assume knowledge about MBean Provider Creation using the WebLogicMBeanMaker, since you already created an Authentication Provider):
You need 3 Files, a XML File with the configuration, the Provider and the Implementation of a Role.
The Config File:
<?xml version="1.0" ?>
<!DOCTYPE MBeanType SYSTEM "commo.dtd">
<MBeanType
Name = "MYRoleMapper"
DisplayName = "MYRoleMapper"
Package = "MY.security"
Extends = "weblogic.management.security. authorization.RoleMapper"
PersistPolicy = "OnUpdate"
>
<MBeanAttribute
Name = "ProviderClassName"
Type = "java.lang.String"
Writeable = "false"
Preprocessor = "weblogic.management.configuration.LegalHelper.checkClassName(value)"
Default = ""MY.security.MYRoleMapperProviderImpl""
/>
<MBeanAttribute
Name = "Description"
Type = "java.lang.String"
Writeable = "false"
Default = ""MY RM provider ""
/>
<MBeanAttribute
Name = "Version"
Type = "java.lang.String"
Writeable = "false"
Default = ""1.2""
/>
</MBeanType>
The Actual Provider MYRoleMapperProviderImpl.java:
public class MYRoleMapperProviderImpl implements RoleProvider, RoleMapper {
private String description;
private static final Map<String, SecurityRole> NO_ROLES = Collections.unmodifiableMap(new HashMap<String, SecurityRole>(1));
private final static String RESSOURCE_URL = "<url>";
private final static String RESSOURCE_EJB = "<ejb>";
private enum rollen {
READER;
}
#Override
public void initialize(ProviderMBean mbean, SecurityServices services) {
description = mbean.getDescription() + "\n" + mbean.getVersion();
}
#Override
public String getDescription() {
return description;
}
#Override
public void shutdown() {
}
#Override
public RoleMapper getRoleMapper() {
return this;
}
#Override
public Map<String, SecurityRole> getRoles(Subject subject, Resource resource, ContextHandler handler) {
Map<String, SecurityRole> roles = new HashMap<String, SecurityRole>();
Set<Principal> principals = subject.getPrincipals();
for (Resource res = resource; res != null; res = res.getParentResource()) {
getRoles(res, principals, roles);
}
if (roles.isEmpty()) {
return NO_ROLES;
}
return roles;
}
private void getRoles(Resource resource, Set<Principal> principals, Map<String, SecurityRole> roles) {
if (resource.getType() == RESSOURCE_URL || resource.getType() == RESSOURCE_EJB) {
roles.put(rollen.READER.toString(), new MYSecurityRoleImpl(rollen.READER.toString(), "READER Rolle"));
}
}
}
And an absolute simple Role Implementation:
package MY.security;
import weblogic.security.service.SecurityRole;
public class MYSecurityRoleImpl implements SecurityRole {
private String _roleName;
private String _description;
private int _hashCode;
public MYSecurityRoleImpl(String roleName, String description)
{
_roleName = roleName;
_description = description;
_hashCode = roleName.hashCode() + 17;
}
public boolean equals(Object secRole)
{
if (secRole == null)
{
return false;
}
if (this == secRole)
{
return true;
}
if (!(secRole instanceof MYSecurityRoleImpl))
{
return false;
}
MYSecurityRoleImpl anotherSecRole = (MYSecurityRoleImpl)secRole;
if (!_roleName.equals(anotherSecRole.getName()))
{
return false;
}
return true;
}
public String toString () { return _roleName; }
public int hashCode () { return _hashCode; }
public String getName () { return _roleName; }
public String getDescription () { return _description; }
}
I have an MVC 4 application that I'm building unit tests for. In my GameController, I have an Action, JoinGame, that requires the current userid. I get this with WebSecurity.CurrentUserId inside the controller.
When I run the unit test for JoinGame, UserId is not being populated. Obviously during a unit test there is no 'current' user. I'm trying to figure out how to mock one.
The first error I got was was System.ArgumentNullException: Value cannot be null. Parameter name; httpContext
After much searching, I found
How to mock httpcontext so that it is not null from a unit test?.
I followed the guidance in that link (created a HttpContextFactory,
which mocked httpcontext and also set the current controller context
to the mocked data). This didn't have any effect.
I then found this Mocking WebSecurity provider
I created a wrapper interface & class for websecurity, and mocked the wrapper & injected the websecuritywrapper into the gamecontroller. This solved the httpContext (though I presently don't really understand why this worked and the HttpContextFactory didn't), however the CurrentUserId returned by the websecuritywrapper is always 0. Even if I hardcode it to 1 insider the websecuritywrapper class (public int CurrentUserId{ get { return 1; }}
Obviously I'm doing something wrong, just not sure what. I've posted code for the unit test, the controller and the wrapper below.
public RedirectToRouteResult JoinGame(int gameid)
{
//_wr is the websecuritywrapper
int UserID = _wr.CurrentUserId; //WebSecurity.CurrentUserId;
// get userteam for this user and this game
UserTeam ut = _UserTeamRepository.GetUserTeam(userteamid:0, gameid: gameid, userid: UserID);
int intUTID = 0;
if (ut == null)
{
// no userteam found, create it
OperationStatus opStatus = _UserTeamRepository.CreateUserTeam(UserID, gameid);
if (opStatus.Status) intUTID = (int)opStatus.OperationID;
}
else {intUTID = ut.Id; }
if (intUTID > 0)
{
return RedirectToAction("Index", "ViewPlayers", new { id = intUTID });
}
else
{
return RedirectToAction("Index", "Game");
}
}
[Test]
public void Game_JoinGame_Returns_RedirectToAction()
{
UserProfile creator = new UserProfile();
UserProfile user = new UserProfile();
Game game = new Game();
ICollection<UserTeam> uteams = null;
UserTeam ut = new UserTeam();
ICollection<UserTeam_Player> utp = null;
List<Game> games = new List<Game>
{
new Game { Id = 1, CreatorId = 1, Name = "Game1", Creator = creator, UserTeams=uteams},
};
List<UserTeam> userteams = new List<UserTeam>
{
new UserTeam {Id=1, UserId = 1, GameId=1, User=user, Game = game, UserTeam_Players=utp}
};
Mock<IGameRepository> mockGameRepository = new Mock<IGameRepository>();
Mock<IUserTeamRepository> mockUserTeamRepository = new Mock<IUserTeamRepository>();
Mock<IWebSecurityWrapper> mockWSW = new Mock<IWebSecurityWrapper>();
mockUserTeamRepository.Setup(mr => mr.GetAllUserTeams()).Returns(userteams);
mockUserTeamRepository.Setup(mr => mr.GetUserTeam(0,1,1)).Returns(ut);
mockUserTeamRepository.Setup(mr => mr.CreateUserTeam(1, 1));
//Arrange
GameController Controller = new GameController(mockGameRepository.Object, mockUserTeamRepository.Object, mockWSW.Object);
// This didn't work
//HttpContextFactory.SetFakeAuthenticatedControllerContext(Controller);
//Act
RedirectToRouteResult result = Controller.JoinGame(1);
Assert.AreEqual("Index", result.RouteValues["action"]);
}
public class WebSecurityWrapper : IWebSecurityWrapper
{
public int CurrentUserId{ get { return WebSecurity.CurrentUserId; }}
public string CurrentUserName { get { return "admin_user"; } } // WebSecurity.CurrentUserName;
public bool HasUserId { get { return WebSecurity.HasUserId; } }
public bool Initialized { get { return WebSecurity.Initialized; } }
public bool IsAuthenticated { get { return WebSecurity.IsAuthenticated; } }
public bool ChangePassword(string userName, string currentPassword, string newPassword){return WebSecurity.ChangePassword(userName, currentPassword, newPassword);}
public bool ConfirmAccount(string accountConfirmationToken) { return WebSecurity.ConfirmAccount(accountConfirmationToken); }
public bool ConfirmAccount(string userName, string accountConfirmationToken) { return WebSecurity.ConfirmAccount(userName,accountConfirmationToken); }
public string CreateAccount(string userName, string password, bool requireConfirmationToken = false) { return WebSecurity.CreateAccount(userName, password, requireConfirmationToken = false); }
public string CreateUserAndAccount(string userName, string password, object propertyValues = null, bool requireConfirmationToken = false) { return WebSecurity.CreateUserAndAccount(userName, password, propertyValues = null, requireConfirmationToken = false); }
public string GeneratePasswordResetToken(string userName, int tokenExpirationInMinutesFromNow = 1440) { return WebSecurity.GeneratePasswordResetToken(userName, tokenExpirationInMinutesFromNow = 1440); }
public DateTime GetCreateDate(string userName) { return WebSecurity.GetCreateDate(userName); }
public DateTime GetLastPasswordFailureDate(string userName){ return WebSecurity.GetLastPasswordFailureDate(userName); }
public DateTime GetPasswordChangedDate(string userName) { return WebSecurity.GetPasswordChangedDate(userName); }
public int GetPasswordFailuresSinceLastSuccess(string userName) { return WebSecurity.GetPasswordFailuresSinceLastSuccess(userName);}
public int GetUserId(string userName){ return WebSecurity.GetUserId(userName);}
public int GetUserIdFromPasswordResetToken(string token) { return WebSecurity.GetUserIdFromPasswordResetToken(token); }
public void InitializeDatabaseConnection(string connectionStringName, string userTableName, string userIdColumn, string userNameColumn, bool autoCreateTables) { WebSecurity.InitializeDatabaseConnection(connectionStringName, userTableName, userIdColumn, userNameColumn, autoCreateTables); }
public void InitializeDatabaseConnection(string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool autoCreateTables) { WebSecurity.InitializeDatabaseConnection(connectionString, providerName, userTableName, userIdColumn, userNameColumn, autoCreateTables); }
public bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, int intervalInSeconds) { return WebSecurity.IsAccountLockedOut(userName, allowedPasswordAttempts, intervalInSeconds); }
public bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, TimeSpan interval) { return WebSecurity.IsAccountLockedOut(userName, allowedPasswordAttempts, interval); }
public bool IsConfirmed(string userName){ return WebSecurity.IsConfirmed(userName); }
public bool IsCurrentUser(string userName) { return WebSecurity.IsCurrentUser(userName); }
public bool Login(string userName, string password, bool persistCookie = false) { return WebSecurity.Login(userName, password, persistCookie = false); }
public void Logout() { WebSecurity.Logout(); }
public void RequireAuthenticatedUser() { WebSecurity.RequireAuthenticatedUser(); }
public void RequireRoles(params string[] roles) { WebSecurity.RequireRoles(roles); }
public void RequireUser(int userId) { WebSecurity.RequireUser(userId); }
public void RequireUser(string userName) { WebSecurity.RequireUser(userName); }
public bool ResetPassword(string passwordResetToken, string newPassword) { return WebSecurity.ResetPassword(passwordResetToken, newPassword); }
public bool UserExists(string userName) { return WebSecurity.UserExists(userName); }
}
The reason that you're getting 0 back when you hard code 1 is because of this line:
Mock<IWebSecurityWrapper> mockWSW = new Mock<IWebSecurityWrapper>();
The version of the IWebSecurityWrapper you're getting is a mock (since you injected it as such). Adding
mockSW.Setup(x=>x.CurrentUserId).Returns(1);
Should get you what you need. Since we're now telling the mock to return 1 when asked for the CurrentUserId
The reason HttpContextFactory didn't work is because the HttpContextFactory implementations I've seen deal with properties on the controller and I suspect your dependency on HttpContext was inside the WebSecurity class itself, hence why you need the wrapper.