Getting a custom claim from JWT - java

I'm trying in to get a custom claim from JWT token in Spring Boot. I am able to get the subject as below:
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
I tried this
public String extractUsername(String token) {
return extractClaim(token, Claims::get("name of the token"));
}
This didn't work. The function get is like getSubjet present under io.jsonwebtoken.claims.

Related

How to mock private native methods in Junit/mockito/powermock

I am new to Junit and trying to write unit testing for a class which has native methods.
public class TokenProvider {
static {
System.loadLibrary("mylib");
}
public Token list(String key) {
TokenProvider tokenprovider = new TokenProvider();
Token token = tokenprovider.listTokens(key);
return token;
}
private native Token listTokens(String key);
}
private native Token listTokens(String key); This method logic is there in mylib library which is written in CPP. I tried like this
public class TestTokenProvider {
#Test
public void testList() {
TokenProvider tokenProvider = new TokenProvider();
Token actual = tokenProvider.list(""); // key is passing as empty as it is not requested for this usecase
Token expected = // need to get list of tokens eg: [{name: "token1", id: "123"}, {name: "token2", id: "1234"}]
assertEquals(actual, expected);
}
}
I am getting "java.lang.unsatisifiedLinkError" Error. Also help me to improve code coverage for TokenProvider.

How to add a query parameter for all requests in Spring Webflux

How can I put query params into all requests in spring webflux avoiding code duplication in all places where I open http connection?
I try to make a configuration for a WebClient bean with a filter that should put a query param in URL every time when I do http call but I cannot find a way how to do it. Is it possible?
Configuration class:
#Configuration
public class IConnectionConfiguration {
#Value("${api.key}")
private String apiKey;
#Value("${api.url}")
private String url;
#Bean
public WebClient webClient(#Autowired ExchangeFilterFunction tokenFilter) {
return WebClient.builder().baseUrl(url)
.filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(tokenFilter);
})
.build();
}
#Bean
public ExchangeFilterFunction tokenFilter() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
//todo put token into request as a query param
return Mono.just(clientRequest);
});
}
}
Api calls layer:
#Service
public class Client {
#Autowired
private WebClient client;
//todo test method
public void testConnection() {
String s = client.get()
.uri(uriBuilder ->
uriBuilder.path("/something/{val}/something")
//todo line which I'm trying to avoid
//.queryParam("token", "token_value")
.build("123-test"))
.retrieve()
.bodyToMono(String.class)
.block();
System.out.println(s);
}
}
Another possibility that does not require overriding or using filter: Use UriComponentsBuilder with the query parameter that should be used for all requests. This instance of UriComponentsBuilder can than be used to instantiate a DefaultUriBuilderFactory for the WebClient.
Based on the code of the question:
public class IConnectionConfiguration {
private static final String TOKEN_QUERY_PARAMETER = "TOKEN";
#Value("${api.key}")
private String apiKey;
#Value("${api.url}")
private String url;
#Bean
public WebClient webClient() {
DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory(uriComponentsBuilder());
return WebClient.builder()
.uriBuilderFactory(defaultUriBuilderFactory)
.build();
}
private UriComponentsBuilder uriComponentsBuilder() {
return UriComponentsBuilder.fromHttpUrl(url)
.queryParam(TOKEN_QUERY_PARAMETER, apiKey);
}
}
The token will now be attached to every request that is issued by the WebClient.
I found another way, without custom UriBuilderFactory:
this.client = WebClient.builder().baseUrl(url)
.filter((request, next) -> {
URI reqUri = request.url()
URI newUri = new URI(reqUri.getScheme()
, reqUri.getAuthority(), reqUri.getPath()
, reqUri.getQuery() + "&key=${apiKey}"
, null)
ClientRequest filtered = ClientRequest.from(request)
.url(newUri)
.build()
next.exchange(filtered)
}).build();
}
This is groovy code but you get the gist, I am sure.
Seems like I found a solution with a uriBuilderFactory override.
Firstly we need an additional class:
public class QueryParamsUriBuilderFactory extends DefaultUriBuilderFactory {
private final MultiValueMap<String, String> queryParams;
public QueryParamsUriBuilderFactory(String baseUrl, MultiValueMap<String, String> queryParams) {
super(baseUrl);
this.queryParams = queryParams;
}
#Override
public UriBuilder builder() {
return super.builder().queryParams(queryParams);
}
}
The next step is to update a configuration:
#Configuration
public class IConnectionConfiguration {
#Value("${api.key}")
private String apiKey;
#Value("${api.url}")
private String baseUrl;
#Bean
public WebClient webClient(UriBuilderFactory uriBuilderFactoryWithAuthenticationToken) {
return WebClient.builder()
.uriBuilderFactory(uriBuilderFactoryWithAuthenticationToken)
.build();
}
#Bean
public UriBuilderFactory uriBuilderFactoryWithAuthenticationToken() {
MultiValueMap<String, String> tokenQueryParam = new LinkedMultiValueMap<>();
tokenQueryParam.add("token", apiKey);
return new QueryParamsUriBuilderFactory(baseUrl, tokenQueryParam);
}
}
Now it will automatically add token query param if we use uri(Function<UriBuilder, URI> var1) function to setup uri. Unfortunately it does not work for uri(URI var1) but we can override all methods related to uri in our new QueryParamsUriBuilderFactory to fix it for all possible methods for uri setup.
Although this is an older question, this is the solution I went with myself in the end:
WebClient webClient = WebClient.builder()
.filter(ExchangeFilterFunction.ofRequestProcessor(
req ->
Mono.just(ClientRequest.from(req).url(
UriComponentsBuilder.fromUri(req.url())
.queryParam("apiKey", "...")
.build(true)
.toUri()
).build()))
)
.build();
This has the following advantages (depending on use case):
It is applied on all requests, whereas the answers using UriBuilderFactory does not work when supplying a new uri template such as when using webClient.get().uri(String uri, Function <UriBuilder, URI> uriFunction)
It uses UriComponentsBuilder for a cleaner way of modifying the URI.
Note that as per its documentation, UriComponentsBuilder created from an existing URI stores query params in raw form, which means that they are already fully encoded. Any new parameters added must also be added in fully encoded form, and in the end build(true) must be called with the true arguments to avoid double encoding.

How to write custom validation in rest api?

In Spring boot.
I want to do field validation and return an error if the input does not exist in the database.
I am trying to write the custom annotation for multiple input fields.
The controller is as below
#RestController
#Api(description = "The Mailer controller which provides send email functionality")
#Validated
public class SendMailController {
#Autowired
public SendMailService sendemailService;
org.slf4j.Logger logger = LoggerFactory.getLogger(SendMailService.class);
#RequestMapping(method = RequestMethod.POST, value = "/sendMail", consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {"text/xml", "application/json"})
#ResponseBody
#Async(value = "threadPoolTaskExecutor")
#ApiOperation("The main service operation which sends one mail to one or may recipient as per the configurations in the request body")
public Future<SendMailResult> sendMail(#ApiParam("Contains the mail content and configurations to be used for sending mail") #Valid #RequestBody MailMessage message) throws InterruptedException {
SendMailResult results = new SendMailResult();
try {
sendemailService.sendMessages(message);
long txnid = sendemailService.createAudit (message);
results.setTxnid (txnid);
results.setStatus("SUCCESS");
} catch(MessagingException | EmailServiceException e) {
logger.error("Exception while processing sendMail " + e);
results.setStatus("FAILED");
// TODO Handle error create results
e.printStackTrace();
} catch(Exception e) {
logger.error("Something went wrong " + e);
results.setStatus("FAILED");
// TODO Handle error create results
e.printStackTrace();
}
return new AsyncResult<SendMailResult>(results);
}
}
one DTO that is mapped with request
public class MailContext {
#NotNull
private String clientId;
#NotNull
private String consumer;
public int getClientId() {
return Integer.parseInt(clientId);
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String toJson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String writeValueAsString = mapper.writeValueAsString(this);
return writeValueAsString;
}
}
Request xml
<mailMessage>
<mailContext>
<clientId>10018</clientId>
<consumer>1</consumer>
</mailContext>
</mailMessage>
I want to write a custom annotation to validate client which exists in the database (table client_tbl) if provided in the request.
consumer: is present in database table cunsumer_tbl
if these not present in database send error message else call service method.
Please suggest how to write such custom annotation with the error.
I know another way to validate this.
Inside your controller, you can register a validator.
#InitBinder
public void setup(WebDataBinder webDataBinder) {
webDataBinder.addValidators(dtoValidator);
}
Where dtoValidator is an instance of Spring Bean, for example, which must implements org.springframework.validation.Validator.
So, you just have to implement two methods: supports() and validate(Object target, Errors errors);
Inside supports() method you can do whatever you want to decide whether the object should be validated by this validator or not. (for example, you can create an interface WithClientIdDto and if the tested object isAssignableFrom() this interface you can do this validation. Or you can check your custom annotation is presented on any field using reflection)
For example: (AuthDtoValidator.class)
#Override
public boolean supports(Class<?> clazz) {
return AuthDto.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
final AuthDto dto = (AuthDto) target;
final String phone = dto.getPhone();
if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(dto.getEmail())) {
errors.rejectValue("email", "", "The phone or the email should be defined!");
errors.rejectValue("phone", "", "The phone or the email should be defined!");
}
if (!StringUtils.isEmpty(phone)) {
validatePhone(errors, phone);
}
}
UPDATE:
You can do that.
Create an annotation
for example:
#Target({ FIELD })
#Retention(RUNTIME)
#Constraint(validatedBy = ClientIdValidator.class)
#Documented
public #interface ClientId {
String message() default "{some msg}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
and implement this validator:
class ClientIdValidator implements ConstraintValidator<ClientId, Long> {
#Override
public boolean isValid(Long value, ConstraintValidatorContext context) {
//validation logc
}
}
More details you can find here: https://reflectoring.io/bean-validation-with-spring-boot/

unable to redirect with post body in java

so i have given a task to create a service that connects to a portal bank! i have to send user credit card information and the price to the bank portal ! and its all happens in back-end. meanwhile our company didnt used Spring MVC and so i cant use it also . i ve found a way to redirect without MVC but i cant make it a POST request with a body .
this is my code
#Path("/ag/v1")
public class RedirectTestClass {
#GET
#Path("/redirect")
public Response sourceSerivce(){
URI uri = UriBuilder.fromUri("/ag/v1/bank").build();
return Response.seeOther(uri).type(MediaType.APPLICATION_JSON_TYPE).entity(new BankInfo("mmad", 1)).allow(HttpMethod.POST).build();
}
#POST
#Path("/bank")
public Response destinationBank(#RequestBody BankInfo test){
return Response.ok(test.getTest()+"hoooray").build();
}
public static class BankInfo{
public BankInfo(String test, int integer) {
this.test = test;
this.integer = integer;
}
#JsonProperty
private String test;
#JsonProperty
private int integer;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public int getInteger() {
return integer;
}
public void setInteger(int integer) {
this.integer = integer;
}
}
}
when i call the redirect serivce with postman i get 405 Method not Allow! how can i redirect it with POST method and body ?
PS: i know for external URL i need to add scheme to my response builder.

Jax RS Authorization

I have an existing code at a class which is extended from javax.ws.rs.core.Application
...
Context childContext = component.getContext().createChildContext();
JaxRsApplication application = new JaxRsApplication(childContext);
application.add(this);
application.setStatusService(new ErrorStatusService());
childContext.getAttributes().put("My Server", this);
...
ChallengeAuthenticator challengeGuard = new ChallengeAuthenticator(null, ChallengeScheme.HTTP_BASIC, "REST API Realm");
//Create in-memory users with roles
MemoryRealm realm = new MemoryRealm();
User user = new User("user", "user");
realm.getUsers().add(user);
realm.map(user, Role.get(null, "user"));
User owner = new User("admin", "admin");
realm.getUsers().add(owner);
realm.map(owner, Role.get(null, "admin"));
//Attach verifier to check authentication and enroler to determine roles
challengeGuard.setVerifier(realm.getVerifier());
challengeGuard.setEnroler(realm.getEnroler());
challengeGuard.setNext(application);
// Attach the application with HTTP basic authentication security
component.getDefaultHost().attach(challengeGuard);
I don't have a web.xml at my code. I would like to add authorization to my code. This: https://restlet.com/technical-resources/restlet-framework/guide/2.3/core/security/authorization does not apply to me since I don't have restlet resources.
How can I implement jax rs authorization into my code?
EDIT 1: Existing code uses restlet JAX-RS extension: https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs
I've tried that at my jax-rs resource class:
#GET
#Path("/")
public String getStatus() {
if (!securityContext.isUserInRole("admin")) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
...
}
However, it throws 403 even I log in with admin user.
EDIT 2:
When I check here: https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs There is a piece of code:
this.setRoleChecker(...); // if needed
This may solve my issue but I don't know how to set a role checker.
PS: I use jersey 1.9 and restlet 2.2.3.
It's not really clear (at least to me :-) ) what you are trying to achieve.
If you have a class which is a subclass of javax.ws.rs.core.Application, you should be able to simply add #RolesAllowed("user") as an annotation to your resource classes, as shown in https://jersey.java.net/documentation/latest/security.html
#Path("/")
#PermitAll
public class Resource {
#RolesAllowed("user")
#GET
public String get() { return "GET"; }
#RolesAllowed("admin")
#POST
public String post(String content) { return content; }
#Path("sub")
public SubResource getSubResource() {
return new SubResource();
}
}
Accessing that resource should prompt you for your credentials. If that doesn't work, then you need to provide a small code sample, which compiles and doesn't do what you want it to do. Then it's easier to see where the problem is and what needs to be done to make it work
I could make it work like that:
Application class:
...
application.setRoles(getRoles(application));
...
public static List<Role> getRoles(JaxRsApplication application) {
List<Role> roles = new ArrayList<>();
for (AuthorizationRoleEnum authorizationRole : AuthorizationRoleEnum.values()) {
roles.add(new Role(application, authorizationRole.toString()));
}
return roles;
}
...
Authorization enum:
public enum AuthorizationRoleEnum {
USER("user"),
ADMIN("admin");
private final String value;
AuthorizationRoleEnum(String value) {
this.value = value;
}
#Override
public String toString() {
return value;
}
}
At my resource classes:
...
#Context
SecurityContext securityContext;
...
allowOnlyAdmin(securityContext);
...
public void allowOnlyAdmin(SecurityContext securityContext) {
if (securityContext.getAuthenticationScheme() != null
&& !securityContext.isUserInRole(AuthorizationRoleEnum.ADMIN.toString())) {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity("User does not have required " + AuthorizationRoleEnum.ADMIN + " role!").build());
}
}
...
You need to implement your RoleChecker using this interface.
As the doc says:
Because the Restlet API does not support its own mechanism for role checks (as e.g. the Servlet API), you must use this inteface if you need role checks in a JAX-RS application.
This interface is used to check, if a user is in a role. Implementations must be thread save.
so as an example of implementation you can do smth like this:
public class MyRoleChecker implements RoleChecker {
public boolean isInRole(Principal principal, String role) {
return principal.getRole().equals(role);
}
}
Edited:
On the other hand as you use the new API, you need to implement SecurityContext and inject it using #Context in your resource methods.
Then you fetch roles list from the storage by username. The storage implementation is up to you. Please refer to this example
#Priority(Priorities.AUTHENTICATION)
public class AuthFilterWithCustomSecurityContext implements ContainerRequestFilter {
#Context
UriInfo uriInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeaderVal = requestContext.getHeaderString("Auth-Token");
String subject = validateToken(authHeaderVal); //execute custom authentication
if (subject!=null) {
final SecurityContext securityContext = requestContext.getSecurityContext();
requestContext.setSecurityContext(new SecurityContext() {
#Override
public Principal getUserPrincipal() {
return new Principal() {
#Override
public String getName() {
return subject;
}
};
}
#Override
public boolean isUserInRole(String role) {
List<Role> roles = findUserRoles(subject);
return roles.contains(role);
}
#Override
public boolean isSecure() {
return uriInfo.getAbsolutePath().toString().startsWith("https");
}
#Override
public String getAuthenticationScheme() {
return "Token-Based-Auth-Scheme";
}
});
}
}
}

Categories

Resources