System.Security.Cryptography.CryptographicException - encryption

When I try to encrypt & decrypt sample text in my WebAPI project the message encrypt successfully but in decryption it dose not work .
I have already set in my startup.cs => services.AddDataProtection();
Here is error message:
System.Security.Cryptography.CryptographicException: The provided payload cannot be decrypted because it was not protected with this protection provider.
[Route("api/[controller]")]
[ApiController]
public class SecurityController : ControllerBase
{
private readonly IDataProtector _protector;
public SecurityController(IDataProtectionProvider protectionProvider)
{
_protector = protectionProvider.CreateProtector("SampleKey");
}
[HttpGet]
public IActionResult Get()
{
string text = "sample text";
string protectedtext = _protector.Protect(text);
string unprotectedtext = _protector.Unprotect(text);
return Ok(new { text = text, Protected = protectedtext, unprotexted = unprotectedtext });
}
}

Related

access httpContextAccessor claims - userid, UPN, email and name

I am using a blazor wasm + core hosted- solution.(.net 6.0)
Here is my project structure:
BlazorApp4.Client
BlazorApp4.Server
BlazorApp4.Shared
I am using windows authentication, since its not supported in wasm, i have enabled windows auth in the server project.
So to access who has logged on I am calling the webapi from the client project.
windowsuser = await httpClient.GetStringAsync("api/wuser");
I have a controller written on the server side
WUserController.cs
namespace BlazorApp4.Server.Controllers
{
[ApiController]
[Route("api/wuser")]
public class WUserController : ControllerBase
{
private readonly ILogger<WUserController> _logger;
WindowsUser? windowsuser = null;
public WUserController(ILogger<WUserController> logger, IHttpContextAccessor httpContextAccessor)
{
windowsuser = new WindowsUser(httpContextAccessor);
_logger = logger;
}
[HttpGet]
public async Task<string> Get()
{
return windowsuser.GetUserName();
}
}
}
WindowsUser.cs
public class WindowsUser
{
private readonly IHttpContextAccessor? _httpContextAccessor;
private readonly string? _userName;
public WindowsUser(IHttpContextAccessor? httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
_userName = httpContextAccessor?.HttpContext?.User.Identity?.Name;
var userId =
httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
}
public string GetUserName()
{
return _userName;
}
}
program.cs (server project)
builder.Services.AddHttpContextAccessor();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
this doesnot work
httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
trying to access upn and email
httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.Upn).Value;
httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.Email).Value;
all are giving null value exception. I guess it is not able to fetch the details.
_userName = httpContextAccessor?.HttpContext?.User.Identity?.Name;
This gives me domainname\username
This is the only property that I am able to get, rest all are null.

Spring controller inheritance and linked requestbody deserealization problems

My objectmapper not working when I use spring controller & class for requestbody inheritation .
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type", visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = RecipeVersion.class, name = "recipe"),
#JsonSubTypes.Type(value = DietVersion.class, name = "diet"),
})
public interface DocumentVersion {
Info getInfo();
void setInfo(Info info);
}
and also
#Data
public class DietVersion implements DocumentVersion {
private LocalizedText warnings;
private List<DietDay> days = new LinkedList<>();
private Info info = new Info();
private String getType() {
return "diet";
}
}
Ok. I have BaseController for diets and recipes
abstract public class BaseController<T extends Document<V>, V extends DocumentVersion> {
abstract protected BaseService<T, V> getService();
#PostMapping("/{docId}/version/last")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication) {
getService().replaceLastVersion(docId, version, authentication);
}
}
and some realizations. example for diet
#Controller
#RequestMapping("/diet")
public class DietController extends BaseController<Diet, DietVersion> {
private final DietService dietService;
#Autowired
public DietController(DietService dietService) {
this.dietService = dietService;
}
#Override
protected DietService getService() {
return dietService;
}
#Override
public void saveVersion(String docId, DietVersion version, Authentication authentication) {
super.saveVersion(docId, version, authentication);
}
}
But when I send json with info, days, type ('diet') to '/diet/1/version/last' then I see in debug mode that my DietVersion pure clear and has no any data. Why ?
How to change settings for objectmapper ?
what if you provide all this in your DietController class.
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication){

Testing login api Spring Security with Postman

I am Working on a spring boot project for an e-commerce website, As a beginner, I try to add spring security in it so the problem is when I try to test my rest login API using postman I have a status code 200 and the body is always the default login page of spring security. I will be thankful for any advice or any solution.
Here is my user class :
public class User implements Serializable {
private static final long serialVersionUID = -2800960695811489984L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String firstName;
private String lastName;
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false)
private String address;
#Column(nullable = false, unique = true)
private String email;
private String password;
private boolean isEnabled;
#Column(name = "role" , nullable = false)
#Enumerated(EnumType.STRING)
private Role role;
Here is my Role enum :
public enum Role {
USER ,ADMIN
}
MyUserDetails Class :
public class MyUserDetails implements UserDetails {
String ROLE_PREFIX ="ROLE_";
private String email;
private String password;
private boolean active;
private Role role;
public MyUserDetails(User user) {
super();
this.email = user.getEmail();
this.password = user.getPassword();
this.active = user.isEnabled();
this.role = role;
}
public MyUserDetails(String email, String password, boolean enabled, Role role) {
super();
}
public static MyUserDetails create(User user) {
return new MyUserDetails(user.getEmail(), user.getPassword() ,user.isEnabled(), user.getRole());
}
Here is MyUserDetailsService :
#Service
#ToString
public class MyUserDetailsService implements UserDetailsService {
UserRepository userRepository;
#Autowired
public MyUserDetailsService(UserRepository userRepository) {
super();
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
if (email == null || email.isEmpty()) {
throw new UsernameNotFoundException("email is Empty");
}
User user = userRepository.findByEmail(email);
if (user != null) {
return user.toCurrentUserDetails();
}
throw new UsernameNotFoundException( email + "is not found !!!");
}
}
Here is my RestController :
#CrossOrigin(origins = "*")
#RestController
#RequestMapping("/home")
public class HomeController {
private AuthenticationManager authenticationManager;
private MyUserDetailsService userDetailsService;
private UserRepository userRepository;
private Jwt jwtUtil;
#Autowired
public HomeController(AuthenticationManager authenticationManager, MyUserDetailsService userDetailsService
, UserRepository userRepository, Jwt jwtUtil) {
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
this.userRepository = userRepository;
this.jwtUtil = jwtUtil;
}
#PostMapping("/signin")
public ResponseEntity<ServerResp> addUser(#RequestBody User user) {
ServerResp response = new ServerResp();
try {
if (Validator.isUserEmpty(user)) {
response.setStatus(ResponseCode.BAD_REQUEST_CODE);
response.setMessage(ResponseCode.BAD_REQUEST_MESSAGE);
} else if (!Validator.isValidEmail(user.getEmail())) {
response.setStatus(ResponseCode.BAD_REQUEST_CODE);
response.setMessage(ResponseCode.INVALID_EMAIL_FAIL_MSG);
} else {
user.setRole(Role.USER);
user.setEnabled(true);
User reg = userRepository.save(user);
response.setStatus(ResponseCode.SUCCESS_CODE);
response.setMessage(ResponseCode.CUST_REG);
}
} catch (Exception e) {
response.setStatus(ResponseCode.FAILURE_CODE);
response.setMessage(e.getMessage());
}
return new ResponseEntity<ServerResp>(response, HttpStatus.ACCEPTED);
}
#PostMapping("/login")
public ResponseEntity<ServerResp> authentification(#RequestBody HashMap<String, String> credential) {
final String email = credential.get(WebConstants.USER_EMAIL);
final String password = credential.get(WebConstants.USER_PASSWORD);
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, password));
} catch (BadCredentialsException e) {
throw new UserNotFoundException(email);
}
final UserDetails userDetails = userDetailsService.loadUserByUsername(email);
final String jwt = jwtUtil.generateToken(userDetails);
ServerResp resp = new ServerResp();
resp.setStatus(ResponseCode.SUCCESS_CODE);
resp.setMessage(ResponseCode.SUCCESS_MESSAGE);
resp.setAUTH_TOKEN(jwt);
return new ResponseEntity<ServerResp>(resp, HttpStatus.OK);
}
}
Here is my Security Configuration Class :
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private MyUserDetailsService userDetailsService;
private JwtFilter jwtFilter;
#Autowired
DataSource datasource;
#Autowired
public SecurityConfiguration(MyUserDetailsService userDetailsService, JwtFilter jwtFilter) {
this.userDetailsService = userDetailsService;
this.jwtFilter = jwtFilter;
}
public SecurityConfiguration(boolean disableDefaults, MyUserDetailsService userDetailsService, JwtFilter jwtFilter) {
super(disableDefaults);
this.userDetailsService = userDetailsService;
this.jwtFilter = jwtFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/resources/**", "/static/**", "/public/**").permitAll()
.antMatchers("/home/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**")
.hasRole("USER")
.anyRequest().authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.formLogin()
//.loginPage("/home/login")
.usernameParameter("email")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.permitAll();
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManagerBean();
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
Here is my user in the database ( MySQL):
user in database
And finally, this is the result of the test in postman :
Test in Postman
Try sending your credentials using Authorization tab in postman, select authorization type to basic Auth.
I do the following steps with my Spring Boot app that has Spring Security. Note than my set up is most likely different from yours but the key here is the csfr token.
These are the steps I am following to do the login in Postman:
Start my Server
Open a chrome tab and go to developer tools and then the Network tab.
In the Network tab, I go to the DOC tab.
I then enter the url: http://localhost:9005/mywarehouse and press enter
This takes me to the Login Form where I then click on Create User
After the user is created I am taken back to the login form and login with the new user credentials.
In Postman, I submit a GET request such as http://localhost:9005/mywarehouse/products which returns the HTML of my login form instead of JSON.
Now back in chrome developer tab on the Doc tab I go to the last entry which is my login and I right click on it and select "Copy as cURL (bash)"
I then go back into Postman and click on the Import button and select "raw text" and then paste.
I then click on Continue and then Import. This opens up a new tab with a POST request and I click on send.
This returns HTML code. I locate the csfr token and copy it and then go to the Body tab and replace the csfr token that is currently there with the one returned from the HTML.
I then resend the POST request created by the Import and then I go back to my original GET request tab and resend and this time I get the JSON response I was expecting.
I have faced this same issue and I got a solution.
In postman go to the settings --> In General section --> turn off the automatically follow redirects.

How Claims are mapped in asp.net core

I am new to asp.net core and I am currently working in the multi-tenant application.I am now stuck because i have no idea of how the claims are mapped in asp.net core
I am getting the above error when in try to access the claims from MIdAuthorizedBaseApiController.
Getting claims from UserController.
My Doubt is when the claims in jwt token are mapped to "User.Claims".I am getting the claims in "UserController.cs" .But i need those claims in MIdAuthorizedBaseApiController.cs inorder to set the "UserContext".
The claims are available in UserController but the UserController itself is inheriting from MIdAuthorizedBaseApiController,but the Claims are not populated there.When i try to access it throws an exception.So, when and how the claims in jwt token are mapped.Please refer the two screenshots above to get my question correctly.
UserController.cs
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class UsersController : MIdAuthorizedBaseApiController
{
[HttpGet]
[ProducesResponseType(200, Type = typeof(BusinessEntities.User))]
[ProducesResponseType(400)]
[ProducesResponseType(401)]
public IActionResult Users()
{
// Get Tenant Id
var claimsList = User.Claims.ToList();
var tenantId = claimsList[4].Value;
// Set the Claims
// _claimsHelper.SetClaims(User.Claims.AsQueryable());
var users = _userManager.Users.Include(u => u.UserRoles).ThenInclude(ur => ur.Role);//.Where(n => n.TenantId.ToString() == tenantId);
// Using "LINQ" to Query only the required properties
var result = from User in users
select new
{
Id = User.Id,
UserName = User.UserName,
Email = User.Email,
PhoneNumber = User.PhoneNumber,
// Roles = String.Join(",", (from roles in User.UserRoles select roles.Role.Name))
};
// Return the result set
if(result != null) {
return Ok(result);
}
return BadRequest(_localizer["2006"]);
}
MIdAuthorizedBaseApiController.cs
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class MIdAuthorizedBaseApiController : AuthorizedApiController
{
public MIdAuthorizedBaseApiController(UserContext usercontext):base(usercontext)
{
PopulateUserContext(usercontext);
}
private void PopulateUserContext(UserContext usercontext)
{
// Getting exception here when i try to populate User.Claims
//here
var claim = HttpContext.User.Claims.First(c => c.Type == "UserId");
//To be replaced with details from token
//usercontext.UserId = Guid.Parse("3C5CD705-8DA0-4536-856B-9F39A6ABC0FA");
usercontext.UserId = Guid.Parse("43200003-6972-4849-B80F-81896C3B5505");
usercontext.Username = Guid.NewGuid().ToString();
//usercontext.TenantId = Guid.Parse("28C914CE-C321-4033-BB87-E9C527249503");
usercontext.TenantId = Guid.Parse("21550810-A8E7-438F-BBF5-CB0755087356");
usercontext.ServerName = DateTime.Now.ToLongTimeString();
}
AuthorizedApiController.cs
using Agility.Core;
using Agility.Web.Filters;
namespace Agility.Web
{
[BusinessExceptionFilter]
public class AuthorizedApiController : BaseApiController
{
public AuthorizedApiController(UserContext userContext);
public UserContext UserContext { get; set; }
}
}
You can use HttpContextAccessor to access the claims .
Modify the MIdAuthorizedBaseApiController to perform the dependency injection of IHttpContextAccessor on the controllers :
public class MIdAuthorizedBaseApiController : AuthorizedApiController
{
public MIdAuthorizedBaseApiController(UserContext usercontext, IHttpContextAccessor httpContextAccessor) : base(usercontext)
{
PopulateUserContext(usercontext, httpContextAccessor);
}
private void PopulateUserContext(UserContext usercontext, IHttpContextAccessor httpContextAccessor)
{
// Getting exception here when i try to populate User.Claims
//here
var claim = httpContextAccessor.HttpContext.User.Claims;
//To be replaced with details from token
//usercontext.UserId = Guid.Parse("3C5CD705-8DA0-4536-856B-9F39A6ABC0FA");
.......
}
}
And the users controller:
public class ValuesController : MIdAuthorizedBaseApiController
{
public ValuesController(UserContext usercontext, IHttpContextAccessor httpContextAccessor) : base(usercontext, httpContextAccessor)
{
}
}
In addition , you could refer to below link which shows how to secure your ASP.NET Core using JWT Bearer authentication ,which use AddJwtBearer middlerware to validate/decode the JWT token :
https://jonhilton.net/security/apis/secure-your-asp.net-core-2.0-api-part-2---jwt-bearer-authentication/

How to get User Name from External Login in ASP.NET Core?

I have set up an external login (Google) in my ASP.NET Core application. I am finding it hard to get the User Name / Email after login. I can see the email stored in AspNetUsers table But I don't see User Name anywhere.
I searched over and found this code:
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
But this is giving me userId as is present in table AspNetUsers. ClaimTypes.Email returns null but the value is present in table (probably this email is something else). I want to fetch User Name and User Email. Is it possible?
Do you have access to SignInManager or can you inject it? If yes, then this is how you would access user id (username), email, first & last name:
public class MyController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public MyController (
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager
)
{
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<IActionResult> MyAction(){
ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
string userId = info.Principal.GetUserId()
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
string FirstName = info.Principal.FindFirstValue(ClaimTypes.GivenName) ?? info.Principal.FindFirstValue(ClaimTypes.Name);
string LastName = info.Principal.FindFirstValue(ClaimTypes.Surname);
}
}
GetUserId extension:
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
return null; //throw new ArgumentNullException(nameof(principal));
string ret = "";
try
{
ret = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
catch (System.Exception)
{
}
return ret;
}
}

Resources