Better way to handle common headers and root? - android-annotations

Is there a better way to set bearer like a global config rather than setting it each time like this:
restClient.setBearerAuth(TokenStore.getInstance().getLocalToken());
The same for root url, is there a global config rather than setting it like this:
String root= Application.getInstance().getApplicationContext().getResources().getString(R.string.whiteLabelApiBaseHost)
restClient.setRootUrl(root);
In retrofit, there is something like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Application.getInstance().getApplicationContext()
.getResources().getString(R.string.whiteLabelApiBaseHost))
Any idea?

To set root url you can use this method, substituting the string with a constant
#Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJackson2HttpMessageConverter.class }, interceptors = MyAuthInterceptor.class)
public interface MyRestClient {
#Get("/events")
EventList getEvents();
}
Note that we set an interceptor in the arguments of the #Rest annotation.
So create a class like this:
#EBean(scope = Scope.Singleton)
public class MyAuthInterceptor implements ClientHttpRequestInterceptor {
#Bean
MyAuthStore authStore;
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
HttpAuthentication auth = new HttpBasicAuthentication(authStore.getUsername(), authStore.getPassword());
headers.setAuthorization(auth);
return execution.execute(request, body);
}
}
Now before executing request MyAuthInterceptor.intercept() is called and you can set your authentication data as you prefer
In your main build.gradle file you can add inside android element
productFlavors {
development {
buildConfigField "String", "SERVICE_URL_BASE", "\"dev.xxx.com/rest\""
}
test {
buildConfigField "String", "SERVICE_URL_BASE", "\"test.xxx.com/rest\""
}
production {
buildConfigField "String", "SERVICE_URL_BASE", "\"production.xxx.com/rest\""
}
}
Then in your #Rest annotation you can use this code to get current flavor value:
#Rest(rootUrl = "https://" + BuildConfig.SERVICE_URL_BASE)
Now you can select what build variant to use (variant = flavor + buildType) to use desired value. To select variant you can use corresponding view, it should be present on the left of android studio.
This technique is useful to avoid creating flavor's package tree only to use different variabiles

Related

Need to Pass the 'value' to my #CustomPreAuthorize annotation and use it in #PreAuthorize("hasAuthority(#myservice.check(#value))")

Currently I am writing my own custom #PreAuthorize annotation.
My case is as follows,
I am running my authorization KeyCloak server that holds the user details, roles and permission
After Validation, I have stored the permission details in GrantedAuthority as follows "{rsname}:GET", "{rsname}:POST" ...
KeyCloak JWT permission structure:
"authorization": {
"permissions": [
{
"scopes": [
"GET",
"DELETE",
"POST"
],
"rsid": "6ae9895f-3766-464f-82c4-44f598ec2a93",
"rsname": "record"
}
]
}
while using #PreAuthorize annotation in controller instead of hardcoding the resource name and scopes, we have to generalize it by getting the details from application.property we have achieved it as follows,
application.property:
auth:
data:
name1: record
name2: device
Property Detail Component class:
#ConfigurationProperties(prefix = "auth")
#Component
public class SecurityProperty {
private Map<String, String> data;
....
}
Controller:
#RequestMapping (method = RequestMethod.GET,value = "/api/records",
produces = {"application/json"})
#PreAuthorize ("hasAuthority (#securityProperty.getData(). get('name1') "
+ "+ ': GET')")
ResponseEntity<List<SomeDTO>> getRecords() {
...Some Logic
}
#RequestMapping(method = RequestMethod.GET,value = "/api/devices",
produces = { "application/json" })
#PreAuthorize("hasAuthority(#securityProperty.getResources().get('name2') "
+ "+ ':GET')")
ResponseEntity<List<SomeDTO>> getDevices() {
...Some Logic
}
So far this is working fine. Since we are creating big project we don't want to write this lengthy #PreAuthorize(XXXX) annotation so decided to create custom annotation that uses the #PreAuthorize.
We have created #CustomPreAuthorize as below
#Retention(RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
#PreAuthorize("hasAuthority(#securityProperty.getResources().get(#resource)"
+ ".concat(':GET'))")
public #interface CustomPreAuthorize {
String resource();
}
And used this in controller
#RequestMapping (method = RequestMethod.GET,value = "/api/devices",
produces = {"application/json"})
#CustomPreAuthorize (resource = "name2")
ResponseEntity<List<SomeDTO>> getDevices() {
...Some Logic
}
Issue:
When I used like this when the API is called I am getting the following error
Failed to evaluate expression 'hasAuthority(#securityProperty.getResources().get(#resource).concat(':GET'))"
So far what I understood is like the resource and scope are not getting recognized in the #PreAuthorize annotation level. Is it possible to read the values like this or is there any alternatives available?
Since there is no reply yet for the required fix, for now we have fixed this by adding the Aspect for the annotation and proceed with manual authority check using the SecurityContextHolder.
#Before("#annotation(CustomPreAuthorize)")
void annotationPointcut() {
//business logic
}
We will check for the other solutions actively and post if we achieve it in more better way.

swagger-ui: How to add a header-param request to every-api

I am new to quarkus and have a bit familiar with swagger-ui. I am able to add a #Parameter to the an endpoint like this:
#Parameter(in = ParameterIn.HEADER, required = true, name = "my-header-id")
But, I would like to add this param to every endpoint. How can I achieve this?
I am using quarkus-smallrye-openapi for the ui.
You can specify parameters on method or class level. If you define the param as class field, then it will be added to all methods of the corresponding endpoint:
#Path("/someendpoint")
public class MyEndpoint {
#HeaderParam("my-header-id")
#Parameter(name = "my-header-id")
String myHeaderId;
#GET
public Response getAll() {return Response.ok().build()}
#GET
#Path("{id}")
public Response someMethod(#PathParam("id") String id) {return Response.ok().build();}
}

Bundling CSS files depending on domain of request?

I have a multi-tenant application and I'm trying to determine the simplest means of controlling which CSS files are bundled based on the url of any incoming request.
I'm thinking I can have some conditional logic inside RegisterBundles() that takes the Url as a string, and bundles accordingly:
public static void RegisterBundles(BundleCollection bundles, string tenant = null) {
if (tenant == "contoso"){
bundles.Add(new StyleBundle("~/contoso.css")
}
}
But I don't know how to pass the string into RegisterBundles, nor even if it's possible, or the right solution. Any help here would be awesome.
It is not possible to do it in RegisterBundles right now. Dynamically generating the bundle content per request will prevent ASP.net from caching the minified CSS (it's cached in HttpContext.Cache).
What you can do is create one bundle per tenant in RegisterBundles then select the appropriate bundle in the view.
Example code in the view:
#Styles.Render("~/Content/" + ViewBag.TenantName)
Edit:
As you said, setting the TenantName in a ViewBag is problematic since you have to do it per view. One way to solve this is to create a static function like Styles.Render() that selects the correct bundle name based from the current tenant.
public static class TenantStyles
{
public static IHtmlString Render(params string[] paths)
{
var tenantName = "test"; //get tenant name from where its currently stored
var tenantExtension = "-" + tenantName;
return Styles.Render(paths.Select(i => i + tenantExtension).ToArray());
}
}
Usage
#TenantStyles.Render("~/Content/css")
The bundle names will need to be in the this format {bundle}-{tenant} like ~/Content/css-test. But you can change the format ofcourse.
I think you are after a solution that allows you to dynamically control the BundleCollection. As far as I know this is currently not possible.
The bundles are configured during app start/configured per the application domain.
A future version of ASP.NET may support this feature i,e using VirtualPathProvider.
Here is some discussion.
See also this SO question.
i'm not good in english, but if you mean you need to handle which CSS file load when you run any URL in your page, i can handle css file in a controler.
First, create a controller name : ResourceController
// CREATE PATH TO CSS FOLDER, I store in webconfig <add key="PathToStyles" value="/Content/MyTheme/" />
private static string _pathToStyles = ConfigurationManager.AppSettings["PathToStyles"];
public void Script(string resourceName)
{
if (!String.IsNullOrEmpty(resourceName))
{
var pathToResource = Server.MapPath(Path.Combine(_pathToScripts, resourceName));
TransmitFileWithHttpCachePolicy(pathToResource, ContentType.JavaScript.GetEnumDescription());
}
}
public void Style(string resourceName)
{
if (!String.IsNullOrEmpty(resourceName))
{
var pathToResource = Server.MapPath(Path.Combine(_pathToStyles, resourceName));
TransmitFileWithHttpCachePolicy(pathToResource, ContentType.Css.GetEnumDescription());
}
}
private void TransmitFileWithHttpCachePolicy(string pathToResource, string contentType)
{
//DO WHAT YOU WANT HERE;
Response.ContentType = contentType;
Response.TransmitFile(pathToResource);
}
//You can handle css or js file...
private enum ContentType
{
[EnumDescription("text/css")]
Css,
[EnumDescription("text/javascript")]
JavaScript
}
In file Global.asax.cs, make sure in application start medthod, in contain the route config
protected void Application_Start()
{
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
Go to routeConfig, add below map to this file (must be add in top of this file) :
routes.MapRoute(
name: "Resource",
url: "resource/{action}/{resourceName}",
defaults: new { controller = "Resource" }
);
Now, create a UrlHelperExtensions class, same path with webconfig file
public static class UrlHelperExtensions
{
public static string Style(this UrlHelper urlHelper, string resourceName)
{
return urlHelper.Content(String.Format("~/resource/style/{0}", resourceName));
}
}
And from now, you can define css file in your view like :
..."<"link href="#Url.Style("yourcss.css")" rel="stylesheet" type="text/css"
/>
Hope this help

mvc4 webapi custom json serializer for specific type

I know MVC4 uses NewtonSoft Json de/serialization. I was wondering how I can exclude a property on serialization to client, without using any of the data annotations like JsonIgnore/DataMemberIngore etc (the assembly is used elsewhere and can't be changed. Can I implement a custom formatter/JsonSerializerSettings/Dynamic ContractResolver etc for a specific object type and then filter out a specific property name?
Any help much appreciated.
Edit. Came up with the following as a first attempt. If anyone has a more elegant solution please let me know...
public class DynamicContractResolver : DefaultContractResolver
{
public DynamicContractResolver()
{
}
protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, Newtonsoft.Json.MemberSerialization.Fields);
if (type == typeof(SomeType))
{
var matchedProp = properties.Where(v=> v.PropertyName=="SomeProperty").FirstOrDefault();
if (matchedProp!=null)
{
properties.Remove(matchedProp);
}
}
return properties;
}
}
Plumbed into global.asax:
HttpConfiguration config = GlobalConfiguration.Configuration;
JsonSerializerSettings serializerSetting = new JsonSerializerSettings
{
ContractResolver = new DynamicContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
config.Formatters.JsonFormatter.SerializerSettings = serializerSetting;
Regards
Phil
This is solvable with a proper overriding
Override a Json function(s) that is in the MVC Controller class.
In this class you can customize the data. (with another mapping,
with reflection, ...)
Create a custom JsonResult class, just override the default one. You
are also able to override there the default serialization which is
going on there.
Now:
You can exclude this data when you already have a JSON
serialized string ... This would be the easiest option. Basically just string operations.
On the other hand you will also be able to call a custom NewtonSoft
serialization and you can do there whatever you want ... Even use custom serializations.

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources