Piranha CMS Setup HealthChecks - health-check

I'm trying to setup HealthCheck's with Piranha CMS. These work fine locally, but once I deploy the endpoints give an 500 internal error. Is there something I am missing with registering HealthCheck's with Piranha CMS. I've tried moving these into the app.UsePiranha(options => and services.AddPiranha(options =>, but still cannot access the HealthCheck endpoints.
Both of these are above the piranha registration.
services.AddHealthChecks()
.AddCheck<DealerUserSyncHealthCheck>("DealerSync Health Check", null, new[] { "DealerSync" })
.AddCheck<VendorSyncHealthCheck>("VendorSync Health Check", null, new[] { "VendorSync" })
.AddCheck<ContactUserSyncHealthCheck>("ContactUserSync Health Check", null, new[] { "ContactUserSync" })
.AddCheck<DbHealthCheck>("Db Health Check", null, new[] { "Db" })
.AddCheck<SendGridHealthCheck>("SendGrid Health Check", null, new[] { "SendGrid" })
.AddCheck<RedisHealthCheck>("Redis Health Check", null, new[] { "Redis" });
OBESettings settings = new OBESettings();
Configuration.Bind(settings);
// Setup Health Check Endpoints
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/DealerSyncCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("DealerSync")
});//.RequireHost(settings.HealthCheckWhitelist);
endpoints.MapHealthChecks("/VendorSyncCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("VendorSync")
});//.RequireHost(settings.HealthCheckWhitelist);
endpoints.MapHealthChecks("/ContactUserSyncCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("ContactUserSync")
});//.RequireHost(settings.HealthCheckWhitelist);
endpoints.MapHealthChecks("/DbCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("Db")
});//.RequireHost(settings.HealthCheckWhitelist);
endpoints.MapHealthChecks("/SendGridCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("SendGrid")
});//.RequireHost(settings.HealthCheckWhitelist);
endpoints.MapHealthChecks("/RedisCheck", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.Contains("Redis")
});//.RequireHost(settings.HealthCheckWhitelist);
});

I've since moved the healthcheck registration above services.AddPiranha and app.UsePiranha registration. I've had to add back in a call to services.AddControllers(); for ConfigureServices and app.UseRouting(); for Configure. Everything now works when deployed.

Related

Test GraphQl passport Context

Okey, this is the repo
What I want to do: Test my protected routes.
Currently, the security of the app is handle by passport, with this strategy: graphql-passport.
I am running my rests with supertest (for the request) and jest
When I build the Apollo Server, i use it to create the context:
import { buildContext } from 'graphql-passport';
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => {
return buildContext({ req, res, User })
},
playground: {
settings: {
'request.credentials': 'same-origin',
},
},
});
This allows me to get the user from the request. Like any authentication with passport works.
passport.use(
new GraphQLLocalStrategy((email, password, next) => {
console.log(`🎫 GraphQLLocalStrategy ${email} 🚔 👮‍♂`)
User.findOne({ email })
.then(user => !user
? next(null, false, 'Invalid email or password')
: user.checkPassword(password) //bcrypt
.then(match => !match
? next(null, false, 'Invalid email or password')
: next(null, user)
)
)
.catch(error => next(error))
}),
);
So far, it works good enough. For every test that i run, I can see my 🎫 GraphQLLocalStrategy ${email} 🚔 👮‍♂ being called. Good!.
For some mutations, like login and update user profile, i am able to do this:
user.mutations.test.js
// * Login for add the user in the context
agent
.post("/graphql")
.send({ query: ` mutation {
${loginQuery(email)}
${updateFirstName}
}`})
.set("Accept", "application/json")
.end((err, {body:{data, errors}}) => {
if (err) return done(err);
const {updateUser} = data;
expect(updateUser).toBeInstanceOf(Object);
expect(updateUser.email).toBe(email);
expect(updateUser.firstName).toBe(newName);
expect(updateUser.rol).toBe("patron");
UserFields.map(checkFields(updateUser));
done();
})
So, in one query, I can send the login mutation and then run the update the first name mutation. Both, works good enough, and according to passport I am logged and I can update the user profile.
What is the issue?? I want to run a loging mutation and after that run a query to get all users.
But, ofcourse, I can not run both at the same time in the request(app).post("/graphql").send() It has to be a one or multiple mutations or a queries... but not both.
The other idea, who doesnt work, is run one, and in the response, run the second one, like this:
const agent = request(app);
agent
.post("/graphql")
.send({ query: `mutation { ${loginQuery(email)} }`})
.end((err, {body:{data}}) => {
if (err) return done(err);
agent
.post("/graphql")
.send({ query: `query { getGuestsQuery() }`})
...
If I try to ask in a second request for a protected route, there is not a way to know that i was authenticated, at least not automatically... Can I make an authenticated request here with supertest
**How can I tell to my tested application that I am authenticated???? **
test("fetch all Guests", async (done) => {
const userAdmin = await User.findOne({rol:"admin"}).exec();
if(!userAdmin) return done('no admin users for testing');
const agent = request.agent(app);
agent
.post('/graphql')
.send({ query: ` mutation { ${loginQuery(userAdmin.email)} }`})
.expect(200)
.end((err, res) => {
if (err) return done(err);
agent
.post("/graphql")
.send({query: `{ getGuests { ${GuestInput.join(' ')} } }`})
.set("Accept", "application/json")
.expect("Content-Type", /json/)
.expect(200)
.end((err, {body:{data}}) => {
if (err) return done(err);
expect(data).toBeInstanceOf(Object);
const {getGuests} = data;
expect(getGuests).toBeInstanceOf(Array);
getGuests.map(user => GuestInput.map(checkFields(user)))
done();
});
});
});

Cannot send Ajax request because of CORS from my UI app to API app even CORS on API is enabled

I have to apps that is located on one origin but they have different ports
One is UI, second is API
When I send requests from 'postman' or from my browser, response code is 200 and all is OK
But when I send request throw ajax from my UI app from browser I get failed request because of Cors
enter image description here
If it's need, in Startup I have Cors policy and use it. This is ConfigureServices Method
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
x => x.MigrationsAssembly("CRM.API")));
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
//.AllowCredentials();
});
});
services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IEmailBirthdayManager, EmailBirthdayManager>();
services.AddSingleton<IAccessManager, AccessManager>();
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
//services.AddMvc().AddNewtonsoftJson(options =>
// options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "CRM.API", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
}
There is Configure method
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
// app.UseMiddleware<AuthorizationMiddleware>();
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireDashboardAuthorizationFilter()}
});
app.UseHangfireServer();
HangfireJobScheduler.ScheduleReccuringJobs();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("AllowAll");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Departments}/{action=GetDepartments}/{id?}");
});
}
And also there is ajax Request to api
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
$.ajax({
url: `https://p-host-crm-2.hostco.ru:1337/api/users/getUserByLogin/gorbunov`,
async: false,
success: function (data) {
console.log("Data Loaded: ");
console.log(data);
}
});
What is more I tried to Use [EnableCors("AllowAll")] in my method and controller
Tried use AddDefaultPolicy" code and "app.UseCors()
Tried use SetIsOriginAllowed(origin => true)
If you ask me what web-server I use, I answer: IIS
In the settings of IIS I haven't found anything
And any suggestions and solutions from internet haven't helped me
Waiting for your answers!
in web config you have to enable cors:config.EnableCors();
and then you have to set origins using attribute on above controller class
:[EnableCors(origins: "*", headers: "*", methods: "*")]

Closing/clearing mock socket between tests

I'm using mock-socket to mock websockets calls.
I've got a test working but it only works for one test, then it says that the mock server is already listening on that url:
describe('mock socket method 1', () => {
let mockSocket;
let mockServer;
beforeEach(() => {
cy.visit('/', {
onBeforeLoad(win: Window): void {
// #ts-ignore
cy.stub(win, 'WebSocket', url => {
mockServer = new Server(url).on('connection', socket => {
console.log('mock socket connected');
mockSocket = socket;
});
if (!mockServer) return new WebSocket(url);
});
},
});
});
afterEach(() => {
mockSocket.close()
});
it('gets a message', () => {
const object = _createSettingsApiPutPayload(defaultSettingsState)
mockSocket.send(JSON.stringify(object));
cy.contains('Motion threshold')
});
it('gets a message', () => {
const object = _createSettingsApiPutPayload(defaultSettingsState)
mockSocket.send(JSON.stringify(object));
cy.contains('Motion threshold')
});
});
If I change the method to before() instead of beforeEach it works, but then I don't get a fresh environment for each test. I tried mockSocket.close() in afterEach() as you can see, but that doesn't work. I've tried cy.reload() but that gives a CORS error!
The error appears to be thrown at
> 15 | ReactDOM.render(
16 | <AppWrapper/>,
17 | document.getElementById('root'),
18 | );
AppWrapper is a AppContainer wrapped in redux's Provider, AppContainer connects App to redux, and here's App:
class App extends Component<AppProps> {
settingsSubscription: W3CWebSocket;
componentDidMount(): void {
// subscribe to websockets
this.settingsSubscription = this.subscribeToSettings(urls.SETTINGS_WS);
}
/**
* Sets up the websockets subscription to the settings.
* #param url the url of the websocket server
* #return the subscription object
*/
subscribeToSettings(url: string): W3CWebSocket {
let settingsSubscription = new W3CWebSocket(url);
settingsSubscription.onopen = () => console.log('WebSocket Client Connected (settings)');
settingsSubscription.onclose = () => console.log('WebSocket Client Disconnected (settings)');
settingsSubscription.onmessage = (message: MessageEvent) => this.handleSettingsMessage(message);
return settingsSubscription;
}
...
}
In the documentation they use mockServer.stop() to stop the mockServer instead of closing the mockSocket. That's what I am doing and most probably what you need as well.
Here's the snippet I am referring to:
// NOTE: this timeout is for creating another micro task that will happen after the above one
setTimeout(() => {
t.is(app.messages.length, 1);
t.is(app.messages[0], 'test message from mock server', 'we have subbed our websocket backend');
mockServer.stop(t.done);
}, 100);
Here's the link to the repo:
https://github.com/thoov/mock-socket/

How to define context object for graphql subscription server

With the normal graphql server we can define the context object like this:
app.use('/graphql', graphqlExpress(async (req) => {
return {
schema,
context: {
app,
params,
}
};
}));
** subscription server **
How can I do the same for the subscription server? (Doing the hybrid http / websocket approach). Can't seem to find a solution from the docs.
new SubscriptionServer({
execute,
subscribe,
schema,
onConnect: (connectionParams, webSocket) => {
console.log(connectionParams);
}
}, {
server,
path: '/subscriptions'
});
You can add a middleware before the execute function and add the required context before resolving the subscription.
It could look like this:
const middleware = (args) => new Promise((resolve, reject) => {
const [schema, document, root, context, variables, operation] = args;
context.app = <your app parameter>;
context.params = <your params>;
resolve(args);
});
SubscriptionServer.create({
schema,
subscribe,
execute: (...args) => middleware(args).then(args => { return execute(...args); }) },
{
server: httpServer,
path: "/subscription",
},
);
As you can see you have all the data from the request in the args of the execute function.

MVC Core How to force / set global authorization for all actions?

How to force / set global authorization for all actions in MVC Core ?
I know how to register global filters - for example I have:
Setup.cs
services.AddMvc(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
and this works fine, but I can't add the same for Authorize:
options.Filters.Add(new AuthorizeAttribute());
I have error:
Cannot convert from 'Microsoft.AspNet.Authorization.AuthorizeAttribute()' to 'System.Type'
(Method .Add() needs IFilterMetadata type)
I know - from similar questions - that this works on MVC4-5... So something must changed on MVC Core...
Someone have any idea?
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
Add the following to your ConfigureServices in StartUp.cs. This is for token validation and force all calls to verify with token.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})`
Add this to Configure method in StartUp.cs.
app.UseAuthentication();
Note: Use [AllowAnonymous] for those where you don't need it

Resources