Skip to content

Commit 01839b4

Browse files
committed
Merge branch 'master' of github.com:Prounckk/samltoawsstskeys into Prounckk-master
2 parents 855a529 + 84e8c35 commit 01839b4

File tree

8 files changed

+128
-69
lines changed

8 files changed

+128
-69
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 2023-mar-20 (v3.3)
4+
* Option to set custom Session Duration
5+
36
## 2022-dec-19 (v3.2)
47
* Fix [#61](https://github.com/prolane/samltoawsstskeys/issues/61). Instead of using the aws http api directly for AssumeRoleWithSAML, this version switches to using the aws sdk. This is to fix processing large SAML Assertions.
58
* Fix [#62](https://github.com/prolane/samltoawsstskeys/issues/62). When the IDP does not add a Session Duration as SAML Assertion Attribute, ignore and continue.

README.md

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SAML to AWS STS Keys Conversion
2-
Google Chrome Extension which converts a SAML 2.0 assertion to AWS STS Keys (temporary credentials). Just log in to the AWS Web Management Console using your SAML IDP and the Chrome Extension will fetch the SAML Assertion from the HTTP request. The SAML Assertion is then used to call the assumeRoleWithSAML API to create the temporary credentials. (AccessKeyId, SecretAccessKey and SessionToken).
2+
Google Chrome Extension, which converts a SAML 2.0 assertion to AWS STS Keys (temporary credentials). Just log in to the AWS Web Management Console using your SAML IDP, and the Chrome Extension will fetch the SAML Assertion from the HTTP request. The SAML Assertion is then used to call the assumeRoleWithSAML API to create the temporary credentials. (AccessKeyId, SecretAccessKey and SessionToken).
33

44
The Chrome Extension can be downloaded here:
55
[Google Chrome Web Store](https://chrome.google.com/webstore/detail/ekniobabpcnfjgfbphhcolcinmnbehde/)
@@ -8,23 +8,25 @@ The Chrome Extension can be downloaded here:
88
99
# Table of Contents
1010
* [Why this Chrome Extension?](#why)
11-
* [Getting Started](#gettingstarted)
12-
* [Create a symlink to your .aws directory (for Windows users)](#symlink)
11+
* [Getting Started from source](#gettingstarted)
1312
* [Plugin Development Notes](#development)
1413
* [Frequently Asked Question](#faq)
1514

1615
## <a name="why"></a>Why this Chrome Extension?
17-
If you don't have any user administration setup within AWS Identity & Access Management (IAM) but instead rely on your corporate user directory, i.e. Microsoft Active Directory. Your company uses a SAML 2.0 Identity Provider (IDP) to log in to the AWS Web Management Console (Single Sign On). Then this Chrome Estension if for you!
16+
If you don't have any user administration setup within AWS Identity & Access Management (IAM) but instead rely on your corporate user directory, i.e. Microsoft Active Directory. Your company uses a SAML 2.0 Identity Provider (IDP) to log in to the AWS Web Management Console (Single Sign On).
17+
Then this Chrome Extension is for you!
1818

19-
You run into trouble as soon as you would like to execute some fancy scripts from your computer which calls the AWS API's. When sending a request to the AWS API's you need credentials, meaning an AccessKey and SecretKey. You can easily generate these keys for each user in AWS IAM. However, since you don't have any users in AWS IAM and don't want to create users just for the sake of having an AccessKey and SecretKey you are screwed. But there is a way to get temporary credentials specifically for your corporate identity.
19+
You run into trouble as soon as you want to execute some fancy scripts from your computer, which call the AWS API. When sending a request to the AWS API, you need credentials, meaning AccessKey and SecretKey. You can quickly generate these keys for each user in AWS IAM. However, since you don't have any users in AWS IAM and don't want to create users just for the sake of having an AccessKey and SecretKey, you are screwed. But there is a way to get temporary credentials specifically for your corporate identity.
2020

21-
The Security Token Service (STS) from AWS provides an API action assumeRoleWithSAML. Using the SAML Assertion given by your IDP the Chrome Extension will call this API action to fetch temporary credentials. (AccessKeyId, SecretAccessKey and SessionToken). This way there is no need to create some sort of anonymous user in AWS IAM used for executing scripts. This would be a real security nightmare, since it won't be possible to audit who did what. This Chrome Extension however will make it super easy for you to just use your corporate identity for executing scripts calling AWS API's.
21+
The Security Token Service (STS) from AWS provides an API action assumeRoleWithSAML. Using the SAML Assertion given by your IDP, the Chrome Extension will call this API action to fetch temporary credentials. (AccessKeyId, SecretAccessKey and SessionToken). This way, there is no need to create some anonymous user in AWS IAM used for executing scripts. This would be an absolute security nightmare since it is impossible to audit who did what. This Chrome Extension, however, will make it super easy for you to use your corporate identity for executing scripts calling AWS API.
2222

23-
## <a name="gettingstarted"></a>Getting Started
24-
TODO
25-
26-
## <a name="symlink"></a>Create a symlink to your .aws directory (for Windows users)
27-
TODO
23+
## <a name="gettingstarted"></a>Getting Started from source
24+
1. Clone this repository
25+
2. Open Chrome and go to `chrome://extensions/`
26+
3. Enable Developer Mode
27+
4. Click on "Load unpacked extension..."
28+
5. Select the folder where you cloned this repository
29+
6. Enjoy!
2830

2931
## <a name="development"></a>Plugin Development Notes
3032
Here are some important notes for development of this plugin.
@@ -57,3 +59,6 @@ With security in mind Google has limited the Chrome browser to only read and wri
5759

5860
3. How long are the credentials valid?
5961
AWS calls this 'session duration'. The default session duration is 1 hour. The maximum session duration is configured in AWS IAM as an attribute of the IAM Role. Your IDP might be configured to pass along an additional SAML claim which requests to apply a custom session duration. This value can be configured to be higher than the default of 1 hour. However, this can never be higher than the configured maximum session duration on the IAM Role as this will result in an error.
62+
63+
4. Create a symlink to your .aws directory
64+
TODO

background/script.js

+27-22
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ importScripts(
66
// Global variables
77
let FileName = 'credentials';
88
let ApplySessionDuration = true;
9+
let CustomSessionDuration = 3600;
910
let DebugLogs = false;
1011
let RoleArns = {};
1112
let LF = '\n';
@@ -15,19 +16,19 @@ let LF = '\n';
1516
loadItemsFromStorage();
1617
// Additionaly on start of the background process it is checked if this extension can be activated
1718
chrome.storage.sync.get({
18-
// The default is activated
19-
Activated: true
20-
}, function(item) {
21-
if (item.Activated) addOnBeforeRequestEventListener();
19+
// The default is activated
20+
Activated: true
21+
}, function(item) {
22+
if (item.Activated) addOnBeforeRequestEventListener();
2223
});
2324
// Additionally on start of the background process it is checked if a new version of the plugin is installed.
2425
// If so, show the user the changelog
2526
// var thisVersion = chrome.runtime.getManifest().version;
26-
chrome.runtime.onInstalled.addListener(function(details){
27-
if(details.reason == "install" || details.reason == "update"){
27+
chrome.runtime.onInstalled.addListener(function(details) {
28+
if (details.reason == "install" || details.reason == "update") {
2829
// Open a new tab to show changelog html page
29-
chrome.tabs.create({url: "../options/changelog.html"});
30-
}
30+
chrome.tabs.create({ url: "../options/changelog.html" });
31+
}
3132
});
3233

3334

@@ -41,7 +42,7 @@ function addOnBeforeRequestEventListener() {
4142
} else {
4243
chrome.webRequest.onBeforeRequest.addListener(
4344
onBeforeRequestEvent,
44-
{urls: ["https://signin.aws.amazon.com/saml"]},
45+
{ urls: ["https://signin.aws.amazon.com/saml"] },
4546
["requestBody"]
4647
);
4748
if (DebugLogs) console.log('DEBUG: onBeforeRequest Listener added');
@@ -73,10 +74,10 @@ async function onBeforeRequestEvent(details) {
7374
samlXmlDoc = decodeURIComponent(unescape(atob(details.requestBody.formData.SAMLResponse[0])));
7475
} else if (details.requestBody.raw) {
7576
let combined = new ArrayBuffer(0);
76-
details.requestBody.raw.forEach(function(element) {
77-
let tmp = new Uint8Array(combined.byteLength + element.bytes.byteLength);
78-
tmp.set( new Uint8Array(combined), 0 );
79-
tmp.set( new Uint8Array(element.bytes),combined.byteLength );
77+
details.requestBody.raw.forEach(function(element) {
78+
let tmp = new Uint8Array(combined.byteLength + element.bytes.byteLength);
79+
tmp.set(new Uint8Array(combined), 0);
80+
tmp.set(new Uint8Array(element.bytes), combined.byteLength);
8081
combined = tmp.buffer;
8182
});
8283
let combinedView = new DataView(combined);
@@ -138,14 +139,15 @@ async function onBeforeRequestEvent(details) {
138139
hasRoleIndex = roleIndex != undefined;
139140
}
140141

141-
// Only set the SessionDuration if it was supplied by the SAML provider and
142-
// when the user has configured to use this feature.
142+
// Set the session duration to the value of CustomSessionDuration if:
143+
// * session duration was not supplied in the SAML assertion
144+
// * user configured to NOT use the session duration supplied in the SAML assertion
143145
if (typeof sessionduration === 'undefined' || !ApplySessionDuration) {
144-
sessionduration = null
146+
sessionduration = CustomSessionDuration
145147
}
146148

147149
// Change newline sequence when client is on Windows
148-
if (navigator.userAgent.indexOf('Windows') !== -1) {
150+
if (navigator.userAgent.indexOf('Windows') !== -1) {
149151
LF = '\r\n'
150152
}
151153

@@ -376,37 +378,40 @@ function outputDocAsDownload(docContent) {
376378
// This Listener receives messages from options.js and popup.js
377379
// Received messages are meant to affect the background process.
378380
chrome.runtime.onMessage.addListener(
379-
function(request, sender, sendResponse) {
381+
function (request, sender, sendResponse) {
380382
// When the options are changed in the Options panel
381383
// these items need to be reloaded in this background process.
382384
if (request.action == "reloadStorageItems") {
383385
loadItemsFromStorage();
384-
sendResponse({message: "Storage items reloaded in background process."});
386+
sendResponse({ message: "Storage items reloaded in background process." });
385387
}
386388
// When the activation checkbox on the popup screen is checked/unchecked
387389
// the webRequest event listener needs to be added or removed.
388390
if (request.action == "addWebRequestEventListener") {
389391
if (DebugLogs) console.log('DEBUG: Extension enabled from popup');
390392
addOnBeforeRequestEventListener();
391-
sendResponse({message: "webRequest EventListener added in background process."});
393+
sendResponse({ message: "webRequest EventListener added in background process." });
392394
}
393395
if (request.action == "removeWebRequestEventListener") {
394396
if (DebugLogs) console.log('DEBUG: Extension disabled from popup');
395397
removeOnBeforeRequestEventListener();
396-
sendResponse({message: "webRequest EventListener removed in background process."});
398+
sendResponse({ message: "webRequest EventListener removed in background process." });
397399
}
398400
});
399401

400402

401403

402404
function loadItemsFromStorage() {
405+
//default values for the options
403406
chrome.storage.sync.get({
404407
FileName: 'credentials',
405408
ApplySessionDuration: 'yes',
409+
CustomSessionDuration: '3600',
406410
DebugLogs: 'no',
407411
RoleArns: {}
408-
}, function(items) {
412+
}, function (items) {
409413
FileName = items.FileName;
414+
CustomSessionDuration = items.CustomSessionDuration;
410415
if (items.ApplySessionDuration == "no") {
411416
ApplySessionDuration = false;
412417
} else {

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"homepage_url": "https://github.com/prolane/samltoawsstskeys",
55
"name": "SAML to AWS STS Keys Conversion",
66
"description": "Generates file with AWS STS Keys after logging in to AWS webconsole using SSO (SAML 2.0). It leverages 'assumeRoleWithSAML' API.",
7-
"version": "3.2",
7+
"version": "3.3",
88
"icons": { "16": "icons/icon_16.png",
99
"32": "icons/icon_32.png",
1010
"48": "icons/icon_48.png",

options/changelog.html

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
<hr>
2121

2222
<div id="divChangelog">
23+
<h3>2023-mar-20<br>v3.3</h3>
24+
<ul>
25+
<li>Option to set custom Session Duration.</li>
26+
</ul>
27+
<br />
28+
<br />
29+
2330
<h3>2022-dec-19<br>v3.2</h3>
2431
<ul>
2532
<li>Fix <a href="https://github.com/prolane/samltoawsstskeys/issues/61" target="_blank">#61</a>. Instead of using the aws http api directly for AssumeRoleWithSAML, this version switches to using the aws sdk. This is to fix processing large SAML Assertions.</li>

options/options.css

+15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ div {
2121
background-color: #fef6e0;
2222
}
2323

24+
#divCustomSessionDuration {
25+
padding-left: 0px;
26+
padding-top: 0px;
27+
padding-bottom: 0px;
28+
padding-right: 0px;
29+
}
30+
31+
.element-visible {
32+
display: block;
33+
}
34+
35+
.element-hide {
36+
display: none;
37+
}
38+
2439
.setting-part {
2540
width: 876px;
2641
border-radius: 10px;

options/options.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@
2525
</div>
2626

2727
<div id="divSessionDuration" class="setting-part">
28-
<label>[OPTIONAL]</label><br>
29-
<label>Apply the SessionDuration requested by the SAML provider</label>
28+
<label>Apply the session duration requested by the SAML provider</label>
3029
<br />
3130
<select name="SessionDuration" id="SessionDuration">
3231
<option value="yes">yes</option>
3332
<option value="no">no</option>
3433
</select>
3534
<br><br>
35+
<div id="divCustomSessionDuration">
36+
<label>Set custom session duration in seconds. Example: 14400 is 4 hours
37+
<br>Note: the requested session duration can NOT be more than MaxSessionDuration set for this role.</label>
38+
<br />
39+
<input type="text" name="CustomSessionDuration" id="CustomSessionDuration" size="40">
40+
<br><br>
41+
</div>
3642
<label>Enable DEBUG logs</label>
3743
<br />
3844
<select name="DebugLogs" id="DebugLogs">

0 commit comments

Comments
 (0)