Dashboard for AppLocker entries.
This was a project i did for Odense Municipalty as an intern. It was my first time creating an Angular application with a C# backend. I grew a lot as a developer, as i only had basic experience in php at the time.
My mentor Morten was a fantastic source of information. At the time he was like a coding wizard to me. I consider myself lucky to have been taught by him. thanks for putting up with my stupid questions at the time mate!
The quality of the project isn't that good (looking back on it) - but it reflects on how i've improved over time. I grew a lot as a developer while creating this project - as it was the first software i made, that was actually going to be used.
It was well recieved, and as far as i'm aware it's included in their stack. Though i feel a bit sorry for the lad that had to fix some of the mess i made.
I worked on this project from October 2017 to February 2018. It had it's ups and downs - but my takeaway from the ordeal was i became a better developer - and my mentor seemed impressed with what i created, considering my background.
Angular frontend
.NET Web API 2.0
Use Visual Studio 2017 for building.
$ git clone git@github.com:martin-juul/odk-applockerlog.git
Note: VS will build Angular for you.
In AppLockerLog.Web you can edit the settings for the API.
- AppLockerLog.Web
- Web.Debug.config - For dev environment
- Web.Release.config - For production environment
SQL Server connection string edit:
<add name="DefaultConnection"
connectionString="server=;database=;user id=;password="
providerName="System.Data.SqlClient"
xdt:Transform="Replace" xdt:Locator="Match(name)"/>
Site urls
<appSettings>
<add key="WebApiEndPoint"
value="protocol://domain.tld/api"
xdt:Transform="SetAttributes(value)"
xdt:Locator="Match(key)" />
<add key="DefaultPage"
value="protocol://domain.tld"
xdt:Transform="SetAttributes(value)"
xdt:Locator="Match(key)" />
</appSettings>
-
ApplockerLog.Web\src\
-
environments
- environment.prod.ts
- environment.ts
Edit the urls for CORS to work.
serviceBaseUrl: ' ',
origin: ' '
200 - Information - Created new entry
201 - Information - Entry completed
300 - Information - Deleted entry
666 - Information - New log entry
API Role | AD Role |
---|---|
incidentReaderGroup | TORG-ODK-W10-USER-APPLOCKERLOG-Read |
incidentResolverGroup | TORG-ODK-W10-USER-APPLOCKERLOG-Write |
You need to be authenticated, before you send a request. This happens automatically with NTLM/Windows Authentication.
In Insomnia or Postman, go to the authentication tab, choose Microsoft NTLM, and put in your credentials before sending requests to the api.
HttpClientL will throw up, if you do not set the response type to text. It allows for empty bodies.
this.http.delete(this.api + endpoint + id, {responseType: 'text'})
GET: /api/auth/getuser
Returns a user object.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"userName": "ODKNET\\marjc",
"incidentReaderGroup": true,
"incidentResolverGroup": true
}
GET: /api/entry/:id
Returns a single log entry.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"id": int,
"userName": string,
"computerName": string,
"ip": string,
"programDescription": string,
"rapportDescription": string,
"note": string|null,
"timeStamp": string,
"editedBy": string|null,
"deniedBy": string|null
}
GET: /api/entries?pageSize=:int&page=:int
Paginated Results. Page starts at 0.
Returns the amount of entries you chose in pageSize, and at the specific page number.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"result": [
{
"id": int,
"userName": string,
"computerName": string,
"ip": string,
"programDescription": string,
"rapportDescription": string,
"note": string|null,
"timeStamp": "2017-12-06T00:00:00",
"editedBy": string|null,
"deniedBy": string|null
},
{
...
}
],
"pagination": {
"totalCount": int,
"totalPages": int,
"prevLink": protocol://url/api/entry?page=int&pageSize=int-1,
"nextLink": protocol://url/api/entry?page=int&pageSize=int+1
}
}
GET: /api/entries?pageSize=:int&page=:int&query=string
Same as paginated results, but filters the result set by Username | Computername | IP
POST: /api/entry
Post a JSON formatted object like this
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"UserName": "",
"ComputerName": "",
"Ip": "",
"ProgramDescription": "",
"RapportDescription": ""
}
The api will return the created object, if successful.
HTTP/1.1 201 CREATED
Content-Type application/json; charset=utf-8
{
"id": int,
"userName": string,
"computerName": string,
"ip": string,
"programDescription": string,
"rapportDescription": string,
"note": string|null,
"timeStamp": string,
"editedBy": string|null,
"deniedBy": string|null
}
PUT|PATCH: /api/entry/:id
Note: This will update all of the fields on the entry, so send the whole object, if you only update a couple of fields.
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"userName": string,
"computerName": string,
"ip": string,
"programDescription": string,
"rapportDescription": string,
"note": string|null,
"timeStamp": string,
"editedBy": string|null,
"deniedBy": string|null
}
Returns the updated object and a 200 OK
status code.
PUT|PATCH: /api/entry/:id/resolved
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"EditedBy": string
}
Returns status code 200 OK
and the object.
PUT|PATCH: /api/entry/:id/denied
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"deniedBy": string
}
Returns status code 200 OK
and the object.
PUT|PATCH: /api/entry/:id/note
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"note": string
}
Returns status code 200 OK
and the object.
DELETE: /api/entry/:id
No need to send any body, just send a DELETE request to the specified url with your ID. Needs incidentResolverGroup.
Returns empty body and status code 200 OK
GET: /api/approval/:id
Returns a single user with assigned user groups
* Server auth using NTLM with user
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"assignedUserGroups": [
{
"id": int,
"approvalID": int,
"group": string
},
{
...
}
],
"id": int,
"userName": string,
"reasoning": string,
"timeStamp": string,
"approver": string
}
GET: /api/entries?pageSize=:int&page=:int
Paginated Results. Page starts at 0.
Returns the amount of entries you chose in pageSize, and at the specific page number.
* Server auth using NTLM with user
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"result": [
{
"assignedUserGroups": [
{
"id": int,
"approvalID": int,
"group": string
},
{
...
}
],
"id": int,
"userName": string,
"reasoning": string,
"timeStamp": string,
"approver": string
}
],
"pagination": {
"totalCount": int,
"totalPages": int,
"prevLink": protocol://url/api/approval?page=int&pageSize=int-1,
"nextLink": protocol://url/api/approval?page=int&pageSize=int+1
}
}
GET: /api/entries?pageSize=:int&page=:int
Same as paginated results, but filters the result set by Username.
NOTE: Currently broken as of 20/12/17
POST: /api/approval
Post a JSON formatted object like this
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"username": string,
"assignedUserGroups":[
{
"group": string
},
{
...
}
],
"reasoning": string
}
The api will return the created object, if successful.
HTTP/1.1 201 CREATED
Content-Type application/json; charset=utf-8
{
"id": 149,
"userName": "marjc",
"reasoning": "",
"timeStamp": "2017-12-20T12:43:30.3469049+01:00",
"approver": "ODKNET\\marjc",
"assignedUserGroups": [
{
"id": 179,
"approvalID": 149,
"group": "ODK-W7-SHAREPOINT-MGMT"
},
{
"id": 180,
"approvalID": 149,
"group": "ODK-RADIUS-GUEST-WIFI"
}
]
}
PUT|PATCH: /api/approval/:id
Note: This will update all of the fields on the entry, so send the whole object, if you only update a couple of fields.
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"userName": string,
"reasoning": string,
"timeStamp": string,
"approver": string,
"assignedUserGroups": [
{
"id": int,
"approvalID": int,
"group" string
}
]
}
Returns the updated object and a 200
OK status code.
PUT|PATCH: /api/approval/:id/note
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"reasoning": string
}
Returns status code 200 OK
and the object.
PUT|PATCH: /api/entry/:id/denied
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"assignedUserGroups": [
{
"group": string
}
]
}
Returns status code 200 OK
and the object.
DELETE: /api/approval/:groupId/group
NOTE: you have to get the specific group id, if you do not know it beforehand, query the approval entry and grab the 'id' from 'assignedUserGroups'
Returns status code 200 OK
and empty body.
DELETE: /api/entry/:id
No need to send any body, just send a DELETE request to the specified url with your ID.
Returns empty body and status code 200 OK
GET: /api/software?pageSize=:int&page=:int
Paginated Results. Page starts at 0.
Returns the amount of entries you chose in pageSize, and at the specific page number.
* Server auth using NTLM with user
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"result": [
{
"id": int,
"name": string,
"vendor": string,
"reasoning": string,
"timeStamp": string,
"createdBy": string,
"state": string
}
],
"pagination": {
"totalCount": 99,
"totalPages": 99,
"prevLink": "protocol://url/api/software?page=int-1&pageSize=int-1",
"nextLink": "protocol://url/api/software?page=int+1&pageSize=int+1"
}
}
"state":
will be either approved or denied.
To only get approved software, set the state GET
variable to 'approved'
GET: /api/software?pageSize=:int&page=:int&state=denied|approved
GET: /api/software?pageSize=:int&page=:int&state=approved|denied&query=string
Same as paginated results, but filters the result set by Name | Vendor. With the set state.
POST: /api/software
Post a JSON formatted object like this
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"name": string,
"vendor": string,
"reasoning": string,
"state": "approved" | "denied"
}
The api will return the created object, if successful.
HTTP/1.1 201 CREATED
Content-Type application/json; charset=utf-8
{
"id": 97,
"name": "Bootcamp Utilities",
"vendor": "Apple Computers Inc.",
"reasoning": "Drivere til Windows fra Apple",
"timeStamp": "2017-12-12T12:00:09.1670294+01:00",
"createdBy": "ODKNET\\marjc",
"state": "approved"
}
PUT|PATCH: /api/software/:id
Note: This will update all of the fields on the entry, so send the whole object, if you only update a couple of fields.
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": 97,
"name": "Bootcamp Utilities",
"vendor": "Apple Computers Inc.",
"reasoning": "Drivere til Windows fra Apple, bruges på A1027",
"timeStamp": "2017-12-12T12:00:09.1670294+01:00",
"createdBy": "ODKNET\\marjc",
"state": "denied"
}
Returns the updated object and a 200
OK status code.
PUT|PATCH: /api/software/:id/note
* Server auth using NTLM with user
Content-Type application/json; charset=utf-8
{
"id": int,
"reasoning": string
}
Returns status code 200 OK
and the object.
DELETE: /api/software/:id
No need to send any body, just send a DELETE request to the specified url with your ID.
Returns empty body and status code 200 OK